C++主动调用析构函数分析
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。
C++主动调用析构函数分析相关推荐
- python在删除对象时会自动调用析构函数_Python面向对象程序设计构造函数和析构函数用法分析...
本文实例讲述了Python面向对象程序设计构造函数和析构函数用法.分享给大家供大家参考,具体如下: 构造函数和析构函数 1.构造方法的使用 很多类都倾向于将对象创建为有初始化状态.因此类可以定义一个名 ...
- 关于c++显示调用析构函数的陷阱
一.文章来由 现在在写一个项目,需要用到多叉树存储结构,但是在某个时候,我需要销毁这棵树,这意味着如果我新建了一个树对象,我很可能在某处希望将这个对象的声明周期终结,自然会想到显示调用析构函数,但是就 ...
- C++ 容器存储对象时,指针调用析构函数触发的一系列BUG
今天给大家分享一篇BUG文章,请耐心看完,也许你以后也会遇到这样的BUG而解决不了! 需求是这样的: 定义一个Student类,里面有私有成员整型和指针! 例如:int age; char *name ...
- C++显示调用析构函数
C++中new的用法及显示调用析构函数 最近被问到了C++内存池的问题,其中不免涉及到在指定内存地址调用对象构造函数以及显示调用对象析构函数的情况. C++中new的用法 new是C++中用于动态内存 ...
- 使用PowerShell调用MTools分析MongoDB性能并发送邮件
使用PowerShell调用MTools分析MongoDB性能并发送邮件 问题描述: 在MongoDB日常运维中,经常需要查看连接数的趋势图.慢查询.Overflow语句.连接来源. 解决方案: 1. ...
- EJB调用原理分析 (飞茂EJB)
EJB调用原理分析 EJB调用原理分析 作者:robbin (MSN:robbin_fan AT hotmail DOT com) 版权声明:本文严禁转载,如有转载请求,请和作者联系 一个远程对象至少 ...
- 深入掌握Java技术 EJB调用原理分析
深入掌握Java技术 EJB调用原理分析 一个远程对象至少要包括4个class文件:远程对象:远程对象的接口:实现远程接口的对象的stub:对象的skeleton这4个class文件. 在 ...
- Alibaba Dubbo框架同步调用原理分析-1
2019独角兽企业重金招聘Python工程师标准>>> 由于Dubbo底层采用Socket进行通信,自己对通信理理论也不是很清楚,所以顺便把通信的知识也学习一下. n 通信理论 计 ...
- delete不调用析构函数的两种情况
1. 所使用的类为预定义类 下面这段函数代码编译运行时没有问题的,不需要CPtr的定义 ---PtrUser.h class CPtr; // 预定义 class CPtrUser { public: ...
最新文章
- 随机森林中的Bootstrap抽样是有放回抽样么?Bootstrap抽样过程描述一下
- 南通大学python期末考试试卷答案_南通大学试卷A(答案及评分标准)
- com.android.dazhihui,大智慧(com.android.dazhihui) - 9.36 - 应用 - 酷安
- springboot+IntelliJ IDEA实现热部署
- zone.js在bootstrap阶段对window对象里一些标准方法的注入逻辑
- c语言哈密顿路径算法,用于检查给定图中是否存在哈密顿循环或路径的C ++程序...
- C/C++基础语法,赶紧收藏好哟~
- javascript让firefox支持innerText
- 使用tcl文件分配管脚
- 学习JavaScript原型应用
- 【C语言】------ 实现三子棋
- MCU中RS485接口设计
- 数学建模解决出版社资源配置问题
- 阿铭Linux_网站维护学习笔记20190415
- 邹恒甫:谈点2002年后海鬼/龟和特聘教授的工资待遇和福利
- iOS项目中用到的一些第三方库
- 后端程序员如何写出优雅的前端试图【Thymeleaf】
- CloudEvents 入门文档
- MySQL数据下载安装教程
- 商业模式方面的经典书籍推荐:《商业模式必读12篇》
热门文章
- comsenzexp php5.3,ComsenzEXP Discuz集成PHP环境
- 目标检测中背景建模方法 [转]
- 苹果加码 iOS 16 的限制:继 AirPlay 后不再支持通过 HDMI 适配器投屏 DRM 内容
- 互联网商道:自己吃饭,别人给钱
- 逻辑运算符的优先级(APP)
- CSS样式优先级顺序
- 呼吸更顺畅的KN95口罩,配色好看安全好用
- android 平板oem,OEM厂商需知 安卓android平板需解决的5大问题
- r7 4800u是标压还是低压 r7 4800u能玩什么游戏
- Android 热修复使用Gradle Plugin1.5改造Nuwa插件