异常处理 续之(堆栈解退、auto_ptr)http://blog.csdn.net/feitianxuxue/article/details/7314079
2015-10-11 15:31
316 查看
1.堆栈解退
当抛出了异常,但还没在特定的作用域中被捕获时,函数调用堆栈便被“解退”,并试图在下一个外层try...catch代码中捕获这个异常。解退函数调用堆栈意味着抛出未捕获异常的那个函数将终止,这个函数中的所有局部变量都将销毁,控制会返回到原先调用这个函数的语句。如果有一个try代码块包含了这条语句,则它就会试图捕获这个异常。如果没有代码块包含这条语句,则堆栈解退再次发生。如果没有任何catch处理器捕获这个异常,则会调用terminate函数,终止程序。
下面的demo演示了堆栈解退:
[cpp] view
plaincopy
#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;
}
运行结果:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201912/09/4c5e8b8d071f8b23fde1d3a28f42209e.gif)
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之前发生异常,就不会自动释放该内存:
[cpp] view
plaincopy
void f()
{
int *ip = new int(42);
//如果在new和delete之间发生异常,并且该异常不被局部捕获,就不会执行delete,永远不回收该内存
delete ip;
}
[cpp] view
plaincopy
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)
[cpp] view
plaincopy
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
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- http中get、post、head对比
- iOS9下修改回HTTP模式进行网络请求
- 静态 http://www.cnblogs.com/lzjsky/archive/2011/01/24/1943199.html
- java中的main函数为什么是静态的 http://zhidao.baidu.com/link?url=k4HpxWZy71GfFpKCNXSvU-Ji9hqbWGWtNryPolNi3ziBPQ
- 静态成员 http://www.verydemo.com/demo_c92_i221125.html
- C++ 类的静态成员详细讲解 http://www.cnblogs.com/morewindows/archive/2011/08/26/2154198.html
- http请求状态
- Angularjs $http 请求数据(get.post)
- 开发与测试分析工具集锦(网络摘要)不断更新
- python 网络编程(二):IO 多路复用
- TCP调优
- 黑马程序员——网络编程
- OKHttp的简单使用
- OKHttp的简单使用
- OKHttp的简单使用
- OKHttp的简单使用
- iOS MVVM 网络请求
- iptables/tc 原理
- TCP/IP、Http、Socket的区别
- C++ TCp通信遇到的无法解析外部符号