首先要明确一点,系统只会自动释放栈内空间,而堆内空间需要用户自己维护。

C++中,除了new来的空间存放在堆内,其他均存放在栈中。

当单纯的创建对象的时候,对象存放在栈中,此时在程序块的}后面,系统会自动调用析构函数,释放掉栈空间。

但是,如果创建了指向new来的一块空间的指针的时候,如果在没有显示释放掉new到的堆空间时,系统是不会自动调用析构函数去释放栈空间中的指针的。

示例代码如下

#pragma once
#include <iostream>
using namespace std;
class CBase

{

public:

CBase(int num){this->num = num;cout<<num<<"号Base类构造函数运行!"<<endl;};

~CBase(){cout<<num<<"号Base类析构函数运行!"<<endl;};
private:
 int num;
};

void main()

{

CBase bobj(1);//析构函数会自动调用

CBase *bptr = new CBase(2);

//delete bptr;//如果没有这句,系统不会自动运行2号的析构函数。

}
此处delete释放的是堆空间中的指针。指针释放后,系统会自动调用析构函数,释放栈中的CBase 2号对象。

Effective C++ 条款6:析构函数里对指针成员调用delete

大多数情况下,执行动态内存分配的的类都在构造函数里用new分配内存,然后在析构函数里用delete释放内存。最初写这个类的时候当然不难做,你会记得最后对在所有构造函数里分配了内存的所有成员使用delete。

然而,这个类经过维护、升级后,情况就会变得困难了,因为对类的代码进行修改的程序员不一定就是最早写这个类的人。而增加一个指针成员意味着几乎都要进行下面的工作:
·在每个构造函数里对指针进行初始化。对于一些构造函数,如果没有内存要分配给指针的话,指针要被初始化为0(即空指针)。
·删除现有的内存,通过赋值操作符分配给指针新的内存。
·在析构函数里删除指针。

如果在构造函数里忘了初始化某个指针,或者在赋值操作的过程中忘了处理它,问题会出现得很快,很明显,所以在实践中这两个问题不会那么折磨你。但是,如果在析构函数里没有删除指针,它不会表现出很明显的外部症状。相反,它可能只是表现为一点微小的内存泄露,并且不断增长,最后吞噬了你的地址空间,导致程序夭折。因为这种情况经常不那么引人注意,所以每增加一个指针成员到类里时一定要记清楚。

另外,删除空指针是安全的(因为它什么也没做)。所以,在写构造函数,赋值操作符,或其他成员函数时,类的每个指针成员要么指向有效的内存,要么就指向空,那在你的析构函数里你就可以只用简单地delete掉他们,而不用担心他们是不是被new过。

当然对本条款的使用也不要绝对。例如,你当然不会用delete去删除一个没有用new来初始化的指针,而且,就象用智能指针对象时不用劳你去删除一样,你也永远不会去删除一个传递给你的指针。换句话说,除非类成员最初用了new,否则是不用在析构函数里用delete的。

说到智能指针,这里介绍一种避免必须删除指针成员的方法,即把这些成员用智能指针对象来代替,比如c++标准库里的auto_ptr。想知道它是如何工作的,看看条款m9和m10。

析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。

  前面的一些例子都没有说明析构函数,这是因为所用到的类在结束时不需要做特别的清理工作。下面的程序给出了一新的Date类,其中包括一个字符串指针,用来表示月份。

  在Date对象的构造函数中,首先用new运算符为字符串month动态分配了内存,然后从内部数组中把月份的名字拷贝给字符串指针month。

析构函数在删除month指针时,可能会出现一些问题。当然从这个程序本身来看,没什么麻烦;但是从设计一个类的角度来看,当Date类用于赋值时,就会出现问题。假设上面的main()修改为“

  

这会生成一个名为today的空的Date型变量,并且把birthday值赋给它。如果不特别通知编译器,它会简单的认为类的赋值就是成员对成员的拷贝。在上面的程序中,变量birthday有一个字符型指针month,并且在构造函数里用new运算符初始化过了。当birthday离开其作用域时,析构函数会调用delete运算符来释放内存。但同时,当today离开它的作用域时,析构函数同样会对它进行释放操作,而today里的month指针是birthday里的month指针的一个拷贝。析构函数对同一指针进行了两次删除操作,这会带来不可预知的后果。

  如果假设today是一个外部变量,而birthday是一个自变量。当birthday离开其作用域时,就已经把对象today里的month指针删除了。显然这也是不正确的。

  再假设有两个初始化的Date变量,把其中一个的值赋值给另一个:

  

问题就更复杂了,当这两个变量离开作用域时,birthday中的month的值已经通过赋值传递给了today。而today中构造函数用new运算符给month的值却因为赋值被覆盖了。这样,birthday中的month被删除了两次,而today中month却没有被删除掉。

自我理解:

C++ 如果类中有一个指针数据成员,而你没有用new, 析构函数是不用delete的。
在类中,int、char 这些只要不是new的,也同样不用释放,系统会自动把他们占的内存释放掉,只有new 的才会手动的去delete。
int char ,这些基本类型,是局部变量,存在于栈上。而一个指针定义的时候,也是在栈上比如int *p;p在栈上,而且p的值也是栈的一个地址。
但是当int *p = new int ;这时候,p这个变量是在栈上的。但是p的值是一个地址,这个地址是堆上的一个地址。
如果不delete p;那么,这个地址会一直被占用着,不能被其他的对象所使用,所以我们用完这个地址,要把这个地址释放掉。

C++析构函数的自动调用问题相关推荐

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

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

  2. python在删除对象时会自动调用析构函数_Python面向对象程序设计构造函数和析构函数用法分析...

    本文实例讲述了Python面向对象程序设计构造函数和析构函数用法.分享给大家供大家参考,具体如下: 构造函数和析构函数 1.构造方法的使用 很多类都倾向于将对象创建为有初始化状态.因此类可以定义一个名 ...

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

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

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

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

  5. c++编码小技巧之函数返回时自动调用

    如何使函数返回时自动执行某段代码? 技巧:可以在函数中定义一个局部对象,在对象的类的析构函数里执行某段代码. 例如: 在brpc::ClosureGuard done_guard(done)对象析构时 ...

  6. php的魔术方式包含哪些(越多越好)? 在何情况下被自动调用?,php笔试题及答案

    php笔试题及答案 T1 一.填空题 1.PHP是用什么语言编写的? :脚本语言 2. LAMP的全称是? :LINUX .APACHE. MYSQL. PHP 3. PHP的三种注释方式? :#./ ...

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

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

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

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

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

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

最新文章

  1. Dell服务器常用管理命令总结
  2. 常考数据结构与算法:两个链表生成相加链表
  3. 主机开启修改BOOT-----支持KVM
  4. C++ Primer 5th笔记(chap 18 大型程序工具)内联命名空间 (inline namespace)
  5. php获取手机的mac地址,Android手机获取Mac地址的方法
  6. Python 自动化,Helium 凭什么取代 Selenium?
  7. SSM整合(相关jar包需求)
  8. OpenCV学习笔记:创建/分配图像、图像读写保存、图像像素点访问修改
  9. java for循环求素数,求1-100的质数,用FOR循环。求救。。
  10. EasyVS -- 快速整理region的Visual Studio扩展
  11. 【跳频通信】基于matlab跳频通信系统仿真【含Matlab源码 967期】
  12. MATLAB基础教程
  13. python公众号接口_python爬取微信公众号
  14. 快来加入阿里云大学【云学院】班级助理—机会稍纵即逝,错过遥遥无期
  15. bip动作捕捉_Mocap动作捕捉系列
  16. 2022年jsonpath的超详细介绍以及在爬取移动端app上的灵活运用
  17. 简单易懂的英语学习思维导图(学习篇)
  18. 出海季,互联网出海锦囊之本地化
  19. 酒店简易管理系统制作详细过程
  20. java pg数据库事务回滚_PostgreSQL事务特性之ROLLBACK

热门文章

  1. Note 7 燃损祸起电池三星将加强安全检查措施
  2. C++ 实现matlab randperm函数
  3. 我们怎样在工作中获得幸福感?
  4. 推导B树的最大高度和最小高度得出B树的高度范围
  5. 1.2 使用电脑测试MC20模块的GPS功能测试
  6. 属性动画+购物车+全选反选+选中计算价格+单个删除
  7. Linux 查询ip地址
  8. 有哪些免费采购信息网站值得推荐?
  9. MiniUI快速入门教程(二)编写第一个MiniUI程序:Hello, world!
  10. 如何感谢领导对我的栽培