当一个void*指向一个class object时,我们对其执行delete操作,会引发未定义行为——可以确定的是该delete操作不会执行object的析构函数,会导致内存泄露。
考虑如下代码:
1  | class Foo{  | 
这份代码编译是没有问题的。
但是,通过gprof分析代码的执行部分会发现,并没有调用Foo的析构函数:
 
上面的代码中,定义了一个GeneralDelete函数,用于统一释放动态分配的对象。该函数输入的参数声明为void*表示着不管传进什么类型的对象,都能统一释放。
这里,在调用GeneralDelete释放foo对象时,首先将它转换成void*类型,再delete。但是问题就出在这里,删除void*类型的foo导致了内存泄露,这是因为当使用delete操作符进行释放对象时,delete需要根据类型信息正确地释放指针所指向的内存块。操作符delete的工作原理大概可以用以下伪代码表示:
1  | delete(obj *ptr){  | 
即,首先调用对象的析构函数,然后释放该对象指针。在调用对象的析构函数前,首先需要知道对象的类型,如果不知道对象的类型,则无法知道该调用谁的析构函数。
由于对象foo传入函数被转换为void*,所以delete不会调用任何析构函数,所以,构造函数中动态分配的内存并没有被释放,导致内存泄露。
C++标准明确规定,针对
void*指针做delete操作会引发未定义行为。所以尽量不要将一个普通对象转换为void*类型,也不要对void*对象做delete操作。
执行正确delete删除操作的代码:
1  | int main(int argc,char* argv[])  |