析构函数在对象的生命结束时,会自动调用,大家所熟知的智能指针就是根据析构函数的这种特性而实现的,包括Qt的内存管理机制,也都是利用了析构函数的这一机制来实现的。c++创始人Bjarne Stroustrup在创造析构函数也是出于这种目的的,可见如果析构函数用的好的话,可以省去我们很多工作量,你不再需要手工调用删除对象使用的堆内存,你只需要把要删除的堆内存放入析构函数就行了,因为当对象离开其生命周期的时候,析构函数会自动调用,C++语言规范是这样规定析构函数的调用的:

Destructors are invoked implicitly (1) for a constructed object with static storage duration (3.7.1) at program termination (3.6.3), (2) for a constructed object with automatic storage duration (3.7.2) when the block in which the object is created exits (6.7), (3) for a constructed temporary object when the lifetime of the temporary object ends (12.2), (4) for a constructed object allocated by a newexpression (5.3.4), through use of a deleteexpression (5.3.5), (5) in several situations due to the handling of exceptions (15.3). A program is illformed if an object of class type or array thereof is declared and the destructor for the class is not accessible at the point of the declaration. Destructors can also be invoked explicitly.

大意是:

析构函数可以由以下五种方式隐含调用:

(1)在静态存储区(也即全局对象或静态对象,这个对象放在程序的数据区)里面构造的对象,当程序结束时,对象的析构函数会自动调用。

(2)在自动存储区(也即局部对象,这个对象放在程序的栈里)里面构造的对象离开其区域时,如1个函数内声明的对象,离开函数作用域时,对象的构造函数会自动调用。

(3)临时构造的对象当离开其生命周期时,该对象的析构函数会调用,此处同(2)。

(4)new构造的对象(即对象在堆区),通过delete删除,析构会调用

(5)在try,catch处理异常的情况下,当在try块中对象,因为异常,进入catch分支,会在catch分支中调用构造函数

以上5种是通过编译器生成的默认调用方式,当然了,还有1种就是可以通过显示的方式调用,也即像调用函数一样调用析构函数

有了上面的介绍,接下来进入我们的主题, delete了,却不调用析构函数的情况,这与上面说的C++的第(4)条规范相悖,下面我以一个简单的示例来说明:

示例由7个文件组成,testa.cpp,testa.h, testb.cpp,testb.h,testapp.h,testapp.cpp,main.cpp

testa.h文件
#ifndef _TEST_A_H
#define _TEST_A_H
class CTestA {
public:CTestA();~CTestA();
};
#endif
testa.cpp文件#include "testa.h"
#include <qdebug.h>
CTestA::CTestA()
{}CTestA::~CTestA()
{qDebug() << "~CTestA()";
}
testb.h文件#ifndef _TEST_B_H
#define _TEST_B_H
class CTestA;
class CTestB {
public:static CTestB *getInstance();CTestA *getTestA();private:CTestB();~CTestB();private:CTestA *pTestA;static CTestB mSelf;
};
#endif
testb.cpp文件
#include "testa.h"
CTestB CTestB::mSelf;
CTestB *CTestB::getInstance()
{return &mSelf;
}
CTestB::CTestB()
{pTestA = new CTestA();
}CTestB::~CTestB()
{delete pTestA;qDebug() << "~CTestB()";
}CTestA *CTestB::getTestA()
{return pTestA;
}
testapp.h文件#ifndef _TEST_APP_H
#define _TEST_APP_H
class CTestA;
class CTestApp {
public:CTestApp(CTestA *pTestA);~CTestApp();
private:CTestA *pTestA;
};
#endif
testapp.cpp文件#include "testapp.h"
#include <qdebug.h>
//#include "testa.h"
CTestApp::CTestApp(CTestA *pTestA)
{this->pTestA = pTestA;
}CTestApp::~CTestApp()
{delete pTestA;qDebug() << "~CTestApp()";
}
main.cpp文件
#include "testb.h"
#include "testcpp.h"
int main(int argc, char *argv[])
{QApplication app(argc, argv);CTestB *pTestB = CTestB::getInstance();CTestApp *pTestApp = new CTestApp(pTestB->getTestA());delete pTestApp;return app.exec();
}

下面是输出结果,

~CTestApp()

说明delete pTestA;后没有调用pTestA的析构函数,当把testapp.cpp文件的//#include "testa.h"注释取消,delete后会调用pTestA析构函数,这是去掉注释后的输出结果:

~CTestA()

~CTestApp()

注以上的编译环境是ming32-make,不知道其他的编译环境会不会出现如此问题,这个留给大家去验证。

下面是反汇编代码,这是在testapp.cpp里面加了testa.h的delete pTestA反汇编代码:

delete pTestA;
0x0040255c  <+8>:                mov    0x8(%ebp),%eax
0x0040255f  <+11>:              mov    (%eax),%ebx
0x00402561  <+13>:             test   %ebx,%ebx
0x00402563  <+15>:               je     0x402575 <~CTestApp+33>
0x00402565  <+17>:              mov    %ebx,(%esp)
0x00402568  <+20>:             call   0x403082 <~CTestA>
0x0040256d  <+25>:                mov    %ebx,(%esp)
0x00402570  <+28>:             call   0x40aa68 <_ZdlPv>

这是在testapp.cpp里面没有加testa.h的delete pTestA反汇编代码:

delete pTestA;
0x00402550  <+8>:                mov    0x8(%ebp),%eax
0x00402553  <+11>:              mov    (%eax),%eax
0x00402555  <+13>:             mov    %eax,(%esp)
0x00402558  <+16>:             call   0x40aa48 <_ZdlPv>

可以看到加了testa.h的反汇编中,调用了析构函数~CTestA,  call 0x403082 <~CTestA>

delete了,析构函数却没有调用相关推荐

  1. 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序

    构造函数.拷贝构造函数和析构函数的的调用时刻及调用顺序 对象是由"底层向上"开始构造的,当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达 ...

  2. vector用erase删除元素时,为什么被删元素的析构函数会被调用更多次?

    vector用erase删除元素时,为什么被删元素的析构函数会被调用更多次? 分类: C++2011-08-18 14:55 720人阅读 评论(0) 收藏 举报 vectoriteratorexce ...

  3. 析构函数什么时候调用

    在这个对象的作用域最后..比如你在main里面声明了一个类A..那么~A()会在main结束时调用.. 如果在自定义的函数f()里面声明了一个A 函数f结束的时候就会调用~A()或者你delete 指 ...

  4. 也谈析构:析构函数何时被调用

    为什么要说"也"?用google搜索"析构函数"是,google会说"约有81,500项符合 析构函数 的查询结果",我最近复习c++是有所 ...

  5. php中析构函数是自动调用吗,php析构函数什么时候调用

    析构函数何时被调用 析构函数在下边3种情况时被调用: 对象生命周期结束,被销毁时: 主动调用delete :(推荐学习:PHP编程从入门到精通) 对象i是对象o的成员,o的析构函数被调用时,对象i的析 ...

  6. php析构函数什么时候调用?

    析构函数何时被调用 析构函数在下边3种情况时被调用: 对象生命周期结束,被销毁时: 主动调用delete :(推荐学习:PHP编程从入门到精通) 对象i是对象o的成员,o的析构函数被调用时,对象i的析 ...

  7. C++析构函数何时被调用

    一般我们都知道构造和析构的次序: 构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对象的构造函数.析构则严格按照与构造相反的次序执行,该次序是唯一的,否则编译器将无法自动执行 ...

  8. C++ 析构函数何时被调用?

    参考文章1:C++ 什么时候调用析构函数 参考文章2:析构函数何时被调用 文章目录 析构函数何时会被调用? 第一种 生命周期结束(在栈区创建的对象,生命周期结束时,会自动执行析构函数) 第二种 del ...

  9. C++ 类析构函数的显示调用和隐式调用

    类的析构函数调用方式 堆和栈 结论 系统在什么情况下不会自动调用析构函数呢? 举例 参考与致谢 堆和栈 为了理解这个问题,我们必须首先弄明白"堆"和"栈"的概念 ...

  10. C++析构函数的自动调用问题

    首先要明确一点,系统只会自动释放栈内空间,而堆内空间需要用户自己维护. C++中,除了new来的空间存放在堆内,其他均存放在栈中. 当单纯的创建对象的时候,对象存放在栈中,此时在程序块的}后面,系统会 ...

最新文章

  1. java编写交通灯思路
  2. VS中添加命令行参数的方法
  3. c++计算eigen随笔(9)-数组、矩阵、向量(2)
  4. 小团队前端部署演化之路
  5. Android之编译提示error: Apostrophe not preceded by
  6. Java ClassLoader getResources()方法与示例
  7. java中的 =运算符_(二十七)、java中的运算符
  8. 云图说 | 通过Helm模板快速部署中间件应用
  9. 使用JavaScript实现简单的小游戏-贪吃蛇
  10. pythonflask接口开发处理多线程请求_flask是如何处理多个访问请求的?
  11. 保存时自动加分号_JavaScript 语句后应该加分号么?
  12. emWin 2天速成实例教程013_修改BUTTON按钮等控件背景皮肤颜色_SetBkColor
  13. 国际会议poster: 海报制作流程 格式介绍
  14. tar.bz2 解压命令以及使用指令
  15. 机顶盒显示网关服务器数据下发超时,智能机顶盒网关服务器数据下发超时
  16. TopFormer 新的语义分割Transformer 结构
  17. ES6新特性-前端面试问题
  18. 明明有 Windows 11,为什么还要用国产操作系统?
  19. APP - 支付宝怎么延时转账?能否撤回转账?
  20. 中国医科大学计算机试题,中国医科大学《计算机应用基础》在线作业和参考答案...

热门文章

  1. 30多套API接口,还怕满足不了你的量化交易需求?
  2. 2020年勒索病毒事件盘点及未来发展趋势
  3. Gartner 2020年十大战略科技发展趋势:边缘赋能、区块链、超自动化、人工智能安全等...
  4. 【图像压缩】基于matlab GUI小波变换图像压缩【含Matlab源码 609期】
  5. 【优化布局】基于matlab遗传算法求解带出入点的车间布局优化问题【含Matlab源码 011期】
  6. 创建项目连接错误_EF6连接Postgresql数据库
  7. 若泽数据 巨人_面部识别巨人拒绝分享有关其算法数据集的详细信息
  8. 让用户输入一个月份,判断这个月是哪个季节?
  9. android 左滑跳转_使用ViewPager实现左右循环滑动及滑动跳转
  10. mysql双主日志_MySQL双主双从配置开启二进制日志