指针转为void*再转回后删除崩溃,如何正确释放内存?
解决void*指针存储后释放崩溃的问题
嘿,这个坑我太熟了!你现在遇到的问题本质是:直接delete void*是C++里的未定义行为——编译器根本不知道这个指针原本指向的是什么类型,没法正确计算要释放的内存大小,也没法调用对应的析构函数(如果是类对象的话)。要解决这个问题,核心思路是让MsgData不仅存储指针本身,还要绑定一个能正确销毁该类型指针的"销毁器"。
具体实现方案
我们可以给MsgData添加一个成员,用来存储对应类型的销毁逻辑,然后通过模板构造函数自动为不同类型绑定正确的销毁方法。这样在释放时,就会调用对应类型的delete(或delete[],如果是数组的话)。
示例代码
#include <functional> class MsgData { private: void* m_raw_ptr; // 存储销毁函数,负责正确释放对应类型的指针 std::function<void(void*)> m_deleter; public: // 模板构造函数:接收任意类型的指针,自动绑定销毁逻辑 template<typename T> explicit MsgData(T* ptr) : m_raw_ptr(ptr) { // 为当前类型生成对应的销毁lambda m_deleter = [](void* data) { delete static_cast<T*>(data); }; } // 针对数组指针的重载(如果需要支持数组) template<typename T> explicit MsgData(T* ptr, std::true_type /* is_array */) : m_raw_ptr(ptr) { m_deleter = [](void* data) { delete[] static_cast<T*>(data); }; } // 禁止拷贝,避免double free风险 MsgData(const MsgData&) = delete; MsgData& operator=(const MsgData&) = delete; // 移动构造/赋值是安全的 MsgData(MsgData&& other) noexcept : m_raw_ptr(other.m_raw_ptr), m_deleter(std::move(other.m_deleter)) { other.m_raw_ptr = nullptr; } MsgData& operator=(MsgData&& other) noexcept { if (this != &other) { // 先销毁当前持有的资源 if (m_raw_ptr) { m_deleter(m_raw_ptr); } m_raw_ptr = other.m_raw_ptr; m_deleter = std::move(other.m_deleter); other.m_raw_ptr = nullptr; } return *this; } // 析构函数自动调用销毁逻辑 ~MsgData() { if (m_raw_ptr) { m_deleter(m_raw_ptr); } } // 获取原始类型指针的模板方法 template<typename T> T* get() const { return static_cast<T*>(m_raw_ptr); } };
为什么这个方案能解决问题?
- 每个
MsgData对象在创建时,都会根据传入的指针类型,绑定一个专属的销毁函数。比如传入bool*时,销毁函数就是delete static_cast<bool*>(data);传入自定义类指针时,会自动调用该类的析构函数。 - 释放操作完全交给
MsgData的析构函数处理,外部不需要直接操作void*指针,从根源上避免了错误的delete调用。
额外注意事项
- 如果需要支持数组指针(比如
bool[]),一定要用delete[],上面的代码已经提供了对应的重载。 - 如果你的指针是通过
malloc分配的,那销毁函数要换成free,可以给MsgData添加一个自定义销毁器的构造重载。 - 确保
MsgData被正确管理(比如作为Message类的成员时,Message的析构函数要正确销毁MsgData对象)。
内容的提问来源于stack exchange,提问作者Mathis
相关产品推荐
相关产品推荐

