C++主动调用析构函数分析

来源:互联网 发布:软件报价方案模板 编辑:程序博客网 时间:2024/06/06 18:29
1、  关于主动调用析构函数;

C++编程规范中都不支持显示的调用析构函数,部分文章中甚至说明析构函数是不能显示调用的,然而执行如下类似的操作编译器并不会报错,而且会调用成功。

pa->~A();

我们先来看看这样的操作会有哪些副作用,然后再讨论存在的意义;

1.       如果在析构函数中显示地释放了堆上的内存,显示调用析构函数会存在重复释放内存错误,例子如下:

class A

{

        char *a;

public:

        A(){a =(char *)malloc(4);}

        ~A()

        {

               free(a);

               printf(“Adeconstructor\n”);

        }

};

int main()

{

        A a;

        a.~A();

        return0;

}

2.       显示的调用析构函数相当于执行了析构函数内容(包括子类析构函数),但是并没有释放内存,也没有摧毁对象;上述的例子可以理解为a对象占用了char *大小的栈内存,占用了4个字节的堆内存,堆内存通过构造函数申请,通过析构函数释放;显示的调用析构函数执行了析构函数,释放掉了堆上的内存,但是并不会释放栈上内存。

3.       使用new操作符的情况有写不同,new操作符可以考虑为两个阶段。

a.  在堆上申请对象本身成员所占内存;

b.  执行构造函数。

考虑如下例子:

class A

{

        char *a;

public:

        A(){a =(char *)malloc(4);}

        ~A()

        {

               free(a);

               printf(“Adeconstructor\n”);

        }

};

int main()

{

        A *a =new A();

        a->~A();

        return0;

}

显然此时编译器不会隐式调用析构函数,所以不会出现重复释放的问题,但是由于a->~A()只会执行析构函数,a指针本身所占的内存不会被释放掉,所以会造成内存泄漏。

 

由以上的分析可知,显示调用析构函数不但不会带来任何好处,还会造成很多奇怪、难以分析的问题,这也是不推荐使用的原因,为什么C++标准不禁止呢?来看一下关于placementnew的用法。

placement new是operator new的一个重载版本;所谓placement new就是在用户指定的内存位置上构建新的对象,这个构建过程不需要额外分配内存,只需要调用对象的构造函数即可。

例子如下:

struct A {…};

struct B {…};

 

A* pa = new A;

pa->~A();

B* pb = new (pa) B;//placement new

以上例子必须要求sizeof(A)>=sizeof(B)。B* pb = new (pa) B并不会申请内存,只是在原来A对象的位置上生成B的对象。

 

更普遍的使用方法如下:

class A{

       …

public:

       show();

};

1)分配内存

char* buff = new char[ sizeof(A) *N+sizeof(int)) ];

memset( buff, 0, sizeof(A)*N +sizeof(int));

 

2)构建对象

A* pa = new (buff)A;

 

3)使用对象

pa->show();

 

4)析构对象,显式的调用类的析构函数。

pa->~A();

 

5)销毁内存

delete [] buff;

 

对于buff这块内存可以反复使用,只要重复2)、3)、4)步骤即可。在C++标准中,对于placementoperator new []有如下的说明:placementoperator new[] needs implementation-defined amount of additional storage tosave a size of array. 所以我们必须申请比原始对象大小多出sizeof(int)个字节来存放对象的个数,或者说数组的大小。

对于效率和容错要求比较高的程序来说placement new是很有用的:

1)  placement new能够有效的解决内存碎片的问题;

2)  malloc、new等申请内存有失败的可能,对有些程序来说是不允许的,而placementnew可以做到;

3)  placement new不需要执行申请内存的过程,速度更快;

 

C++标准STL就有使用placement new的情况,不过不是在特殊情况下比如自己编写高效率库、需要自己管理内存池时不推荐使用placement new。