栈展开(stack unwinding)在destructors中的exceptions
抛出异常与栈展开(stack unwinding)
抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句。首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常。如果不能处理,就退出当前函数,并且释放当前函数的内存并销毁局部对象,继续到上层的调用函数中查找,直到找到一个可以处理该异常的catch。这个过程称为栈展开(stack unwinding)。当处理该异常的catch结束之后,紧接着该catch之后的点继续执行。
1. 为局部对象调用析构函数
如上所述,在栈展开的过程中,会释放局部对象所占用的内存并运行类类型局部对象的析构函数。但需要注意的是,如果一个块通过new动态分配内存,并且在释放该资源之前发生异常,该块因异常而退出,那么在栈展开期间不会释放该资源,编译器不会删除该指针,这样就会造成内存泄露。
2. 析构函数应该从不抛出异常
在为某个异常进行栈展开的时候,析构函数如果又抛出自己的未经处理的另一个异常,将会导致调用标准库terminate函数。通常terminate函数将调用abort函数,导致程序的非正常退出。所以析构函数应该从不抛出异常。
3. 异常与构造函数
如果在构造函数对象时发生异常,此时该对象可能只是被部分构造,要保证能够适当的撤销这些已构造的成员。
4. 未捕获的异常将会终止程序
不能不处理异常。如果找不到匹配的catch,程序就会调用库函数terminate。
因此,在有可能发生异常的函数中,可以利用“智能指针”auto_ptr来防止内存泄露。参考如下程序。
#include <iostream>
#include <memory>
using namespace std;class A{int num;
public:A(int i):num(i){cout<<"this is A's constructor, num="<<num<<endl;}~A(){cout<<"this is A's destructor, num="<<num<<endl;}void show(){cout<<num<<endl;}
};void autoptrtest1(){A* pa=new A(1);throw 1;delete pa;
}void autoptrtest2(){auto_ptr<A> pa(new A(2));pa->show();throw 2;
}int main(){try{autoptrtest1();} catch(int){cout<<"there is no destructor invoked"<<endl;}cout<<endl;try{autoptrtest2();}catch(int){cout<<"A's destructor does be invoked"<<endl;}
}
程序的输出结果:
this is A’s constructor, num=1
there is no destructor invoked
this is A’s constructor, num=2
2
this is A’s destructor, num=2
A’s destructor does be invoked
在解读上面的这段程序的时候,要注意以下几点。
(1)在函数autoptrtest1()中,由于异常的发生,导致delete pa;无法执行,从而导致内存泄露。
(2)auto_ptr实际上是一个类模板,在名称空间std中定义。要使用该类模板,必须包含头文件memory。auto_ptr的构造函数可以接受任何类型的指针,实际上是利用指针类型将该类模板实例化,并将传入的指针保存在auto_ptr< T>对象中。
(3)在栈展开的过程中,auto_ptr< T>对象会被释放,从而导致auto_ptr< T>对象的析构函数被调用。在该析构函数中,将使用delete运算符将保存在该对象内的指针所指向的动态对象被销毁。这样,就不会发生内存泄露了。
(4)由于已经对*和->操作符进行了重载,所以可以像使用普通的指针变量那样使用auto_ptr< T>对象,如上面程序中的pa->show()。这样可以保留使用指针的编程习惯,方便程序猿编写和维护。
转自下面两篇博客:
http://www.cnblogs.com/zhuyf87/archive/2012/12/23/2829725.html
http://blog.csdn.net/K346K346/article/details/50157297
//————————-分界线——————————-
在这里顺便也把异常关于在析构函数内的内容写一下学习笔记。
内容是more effective 条款11:禁止exceptions流出destructors之外。
class Session{
pubilc:Session();~Session();...
private:static void logCreation(Session *obj);static void logDestruction(Session *obj);
}
Session::~Session(){logDestruction(this);
}
如果在~Session调用时logDestruction抛出一个exception,这个exception不会被Session destructor捕捉,然后就会发生栈展开,传播到destructor的调用端,但是万一这个destructor本身是因为其他某个exception而被调用的,terminate函数便会被自动调用,于是程序终止。
解法:
Session ::~Session(){
try{
logDestruction(this);
}
catch(…){}
}
这个语句块阻止了logDestruction抛出的exception传出Session destructor之外。如果一个Session object因为栈展开而被销毁,terminate并不会被调用。
好处:
1.避免terminate函数在exception传播过程的栈展开机制中被调用。
2.可以协助确保destructor完成其应该完成的所有事情。
栈展开(stack unwinding)在destructors中的exceptions相关推荐
- 栈展开(stack unwinding)
栈展开(stack unwinding)的定义 抛出异常时,将暂停当前函数的执行,开始查找匹配的 catch 子句.首先检查 throw 本身是否在 try 块内部,如果是,检查与该 try 相关的 ...
- c++抛出异常与栈展开(stack unwinding)
抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句.首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常.如果不能处理,就退出当前函数 ...
- noexcept与栈展开(stack unwinding)
noexcept说明 在C++11之后,表示函数不会抛出异常的动态异常声明throw()被新的noexcept异常声明所取代. 该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化 ...
- 抛出异常与栈展开(stack unwinding)
抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句.首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常.如果不能处理,就退出当前函数 ...
- java中stack heap_java虚拟机中的堆(heap)、栈(stack)、方法区(method area)
1.堆区 存储的全部是对象,每个对象都包含一个与之对应的class的信息.(class的目的是得到操作指令) jvm只有一个heap区,被所有线程共享,不存放基本类型和对象引用,只存放对象本身 堆的优 ...
- C++ 栈展开如何防止内存泄露
在栈展开(stack unwinding)是指,如果在一个函数内部抛出异常,而此异常并未在该函数内部被捕捉,就将导致该函数的运行在抛出异常处结束,所有已经分配在栈上的局部变量都要被释放.如果被释放的变 ...
- C++中的stack类、QT中的QStack类
C++中的stack 实现一种先进后出的数据结构,是一个模板类. 头文件 #include<stack> 用法(以int型为例): stack <int> s; //定义一个i ...
- 堆(heap)与栈(stack)的区别(一)
堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收,但它与数据结构中的堆不是一回事,分配方式类似于链表. 栈(stack):由编译器自动分配和释放,存函数的参数值, ...
- java中的stack类和C++中的stack类的区别
文章目录 1 java中的stack类和C++中的stack类的区别 1.1 java中的stack类 1.2 C++中的stack类 1.3 分析 不经意间想到了这个问题,存到栈中的是对象的引用,还 ...
最新文章
- 自学Java-运算符
- 【网址收藏】win10 VirtualBox安装CentOS 7教程
- 【重构】微信小程序倒计时组件
- 桌面图标摆放图案_用图标制作醒目的图案
- 请求接受json tp5_关于jq jsonp跨域请求错误处理bug
- python gui界面实例_Python界面(GUI)编程PyQt5工具栏和菜单
- VSCode配置ESLint
- 5月购机指南!新机流畅度排行榜:第一名实至名归
- java ajax异步验证,【求助】真的不会做了。。关于AJAX异步验证的问题。。
- Atlas 调用web service
- Caffe学习3:Layer
- android源码 分享1
- word2016 插入书签域
- 关于环信客服的集成与使用
- 如何在本地运行jsp文件
- POJ 2248【加法链】
- 点到线段的最短距离——矢量法
- MTU TTL RTT
- OCX控件全屏、恢复
- JVM内存区域和垃圾收集器