void *在c/c++中可以说是万金油的存在,无论什么类型的数据都可以塞给它,但是释放的时候,却需要知道具体的类型,才能调用delete去释放,直接delete void *的指针是未定义的有可能会导致内存泄露。
如果编译器支持c++17, 可用std::any来代替void *, 如果编译器只支持c++ 11可以用shared_ptr来替代。下面以shared_ptr来做为例子
释放void *要知道原来申请的对象是什么类型,伪代码如下:
void *p = new xx;
if p is A:
delete (A *)p;
else if p is int
delete (int *)p
else ....
替换成shared_ptr如下
std::shared_ptr<xx> p = std::make_shared<A>(xx);
就一行,不需要手动去释放,生命周期到了,会自动释放内存。
具体c++代码如下,其中有注释
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base();
virtual ~Base();
};
Base::Base()
{
std::cout << __func__ << std::endl;
}
Base::~Base()
{
std::cout << __func__ << std::endl;
}
class A : public Base
{
public:
A(char c);
virtual ~A();
char m_c;
};
A::A(char c)
:m_c(c)
{
std::cout << __func__ << std::endl;
}
A::~A()
{
std::cout << __func__ << std::endl;
}
int main(int argc, char **argv)
{
std::cout << "1-----" << std::endl;
std::shared_ptr<void> data = std::make_shared<Base>();
std::cout << "1-----" << std::endl;
data = std::make_shared<int>(1);
std::cout << "1-----" << std::endl;
std::cout << std::endl << "2--------" << std::endl;
std::shared_ptr<void> dataA = std::make_shared<A>('a');
std::cout << "2--------c:" << (reinterpret_cast< A* >(dataA.get()))->m_c << std::endl;
dataA = std::make_shared<std::string>("OK"); // 重新赋值dataA时,原先的内存会被自动释放, 这里会先调用A的析构函数
std::cout << "2--------" << std::endl;
std::cout << std::endl << "int------" << std::endl;
std::shared_ptr<int> dataB = std::make_shared<int>(100);
std::cout << "int------:" << *dataB << std::endl;
// 直接delete void *的指针,有可能会内存泄露的
std::cout << std::endl << "void *------" << std::endl;
long n = 10;
void *dataC = (void *)n; // 这里没有分配动态内存空间,所以后面
std::cout << "n:" << long(dataC) << std::endl;
dataC = new A('c');
if (dataC)
{
delete dataC; // deleting ‘void*’ is undefined
dataC = NULL;
}
std::cout << "void *------" << std::endl << std::endl;
return 0;
}
编译后运行,输出
1-----
Base
1-----
~Base //使用shared_ptr这里自动释放
1-----
2--------
Base
A
2--------c:a
~A
~Base //使用shared_ptr这里自动释放
2--------
int------
int------:100
void *------
n:10
Base
A
void *------ // 使用delete void *的方式,这里A申请内存后结束生命周期时,没有调用析构函数进行内存释放。
作者:帅得不敢出门