异常处理 续之(堆栈解退、auto_ptr)
来源:互联网 发布:卖家设置淘宝客 编辑:程序博客网 时间:2024/06/01 13:15
1.堆栈解退
当抛出了异常,但还没在特定的作用域中被捕获时,函数调用堆栈便被“解退”,并试图在下一个外层try...catch代码中捕获这个异常。解退函数调用堆栈意味着抛出未捕获异常的那个函数将终止,这个函数中的所有局部变量都将销毁,控制会返回到原先调用这个函数的语句。
如果有一个try代码块包含了这条语句,则它就会试图捕获这个异常。如果没有代码块包含这条语句,则堆栈解退再次发生。如果没有任何catch处理器捕获这个异常,则会调用terminate函数,终止程序。
下面的demo演示了堆栈解退:
#include <iostream>#include <stdexcept>using namespace std;void fun3() throw (runtime_error){ cout<<"In fun 3"<<endl; throw runtime_error("runtime_error in fun3");}void fun2() throw (runtime_error){ cout<<"fun3 is called inside fun2"<<endl; fun3();}void fun1() throw (runtime_error){ cout<<"fun2 is called inside fun1"<<endl; fun2();}int _tmain(int argc, _TCHAR* argv[]){ try { cout<<"fun1 is called inside main"<<endl; fun1(); } catch(runtime_error &error) { cout<<"Exception occurred: "<< error.what()<<endl; cout<<"exception handled in main"<<endl; } system("pause"); return 0;}
运行结果:
2.构造函数、析构函数与异常处理
探讨一个问题:如果在构造函数中检测到错误,会发生什么事情?
例如:当new运算符用于无法分配所需的内存来保存对象的内部表示而失败时,这个对象的构造函数该如何响应?
在构造函数抛出异常前,会调用作为这个对象的一部分而构建的任何成员对象的析构函数。在抛出异常前,会调用try代码块中构建的每一个自动对象的析构函数。当异常处理器开始执行的时刻,会保证已经完成了堆栈解退。如果作为堆栈解退的结果而被调用的析构函数抛出了异常,则会调用terminate函数。
如果对象具有成员对象,并且如果外层对象被完全构建之前就抛出了异常,则在异常发生之前,会为已经构建的成员对象执行析构函数。
异常可能会阻止释放资源的代码的执行,从而导致内存泄露。解决这一问题的一种技术是:初始化一个局部对象,以获取这个资源。当异常发生时,就会调用这个对象的析构函数,并可释放资源。
3.Auto+ptr类与动态内存分配
auto_ptr类是一个接受一个类型参数的模板,它为动态分配对象提供了异常安全。
动态内存分配,就是将这块内存的地址赋予指针,通过这个指针来操作这块内存。当内存不在需要时,使用delete运算符来清理这块内存。
如果在内存分配成功之后,delete语句执行之前发生了异常,就可能导致内存泄露。C++标准库在头文件<memory>中提供了类模板auto_ptr,用于处理这种情况。
auto_ptr类的对象维护着指向动态分配内存的指针。当调用auto_ptr对象的析构函数时(当auto_ptr对象超出作用域范围时,就会调用析构函数),它对指针数据成员执行delete操作。
auto_ptr对象只能保存一个指向对象的指针,并不能用于指向动态分配的数组,使用auto_ptr对象指向动态分配的数组会导致未定义的运行时行为。
为异常安全的内存分配使用auto_ptr
如果通过常规指针分配内存,而且在执行delete之前发生异常,就不会自动释放该内存:
void f(){ int *ip = new int(42); //如果在new和delete之间发生异常,并且该异常不被局部捕获,就不会执行delete,永远不回收该内存 delete ip;}
void f(){ auto_ptr<int> ap(new int(42)); //编译器保证在展开栈越过f之前运行ap的析构函数}
下面是一个面试题,我在CSDN论坛上看到的:
来自(http://topic.csdn.net/u/20120229/20/d5442409-f8c5-45a2-90d7-6c746859ef4a.html)
template <typename T> //auto_ptr是智能指针,所有权转移void Func2(std::auto_ptr<T> v1, std::auto_ptr<T> v2, std::auto_ptr<T> v3){ <…>}template <typename T> bool Func1(){ try { std::auto_ptr<T> p(new T); Func2(p, std::auto_ptr<T> (new T), std::auto_ptr<T>(new T)); //调用Func2后,P就是NULL了 p->SomeMethod(); //出错了 return true; } catch(const std::bad_alloc&) { return false; }}
问题:
Do you see any problems in this code?
Is this code an exception safe?
If you see any problems please mark all of them (by using the following style: line of code – description of the problem; for example: “printf(s) – uninitialized variable s”).
在论坛上看到一句话:
<<C++标准程序库>>第42页第一自然段:...如果auto_pro以by value方式被当做一个参数传递给函数,...此时被调用的参数获得了这个auto_pro的拥有权,如果函数不再将它传递出去,它所指的对象就会在函数退出时被删除...
参考资料:《c++程序员教程》 电子工业出版社 PP463-P470 《c++ primer 中文版 第4版》 人民邮电出版社 P580-596
- 异常处理 续之(堆栈解退、auto_ptr)
- 异常处理 续之(堆栈解退、auto_ptr)http://blog.csdn.net/feitianxuxue/article/details/7314079
- Android开发之异常处理篇(一):SDK Manager闪退的解决方法
- 分析堆栈,处理异常
- 【c++系列12】异常安全之auto_ptr
- C++异常安全之std:auto_ptr
- c++ 堆栈解退的概念
- Android 任务和回退堆栈---处理亲缘关系
- Android 任务和回退堆栈---处理亲缘关系
- auto_ptr与异常抛出
- .net异常之 StackOverflowException(堆栈溢出)
- 智能指针(二)之auto_ptr
- 异常堆栈
- JAVA异常之异常处理
- Android 任务和回退堆栈---清除回退堆栈
- Android 任务和回退堆栈---清除回退堆栈
- C++异常处理及函数堆栈信息打印
- [c++基础] 内存,堆栈,资源,异常处理相关问题
- 生命的意义
- Linux网络驱动程序编写(二) 嵌入式Linux网络驱动程序开发设计 Linux网络驱动程序编写(二)
- linux fcitx4
- 一台电脑上启动两个tomcat方法
- 队列
- 异常处理 续之(堆栈解退、auto_ptr)
- string的使用
- perl语言svg制图模板化
- VIM使用小技巧-重新载入文件
- linux的qos机制 - dm-ioband篇 (3)
- android笔记,山寨版摇动判断算法的设计过程。
- Jboss 5关闭群集
- 在shell中捕捉信号的trap命令
- 什么是函数指针数组?——学习C语言基本技能之分清主语、定语