异常(exceptions)
#
# 异常(exceptions)
# Item 9:利用 destructors避免泄漏资源
利用destructor来避免资源的泄露(什么是资源泄露?没有delete的指针), 最好还是使用智能指针的类来处理会比较好;
要么catch到exception之后, 要及时释放资源, 避免资源泄露;
要么就在destructor里面, 增加资源的释放, 即使遇到异常, 退出的时候也会调用析构函数里面的delete;
虚基类(多态基类)一定要有自己的虚dtor函数【Effectie C++里面也用到了】
使用智能指针, auto_ptr(), shared_ptr(), weak_ptr() 注意他们相关的实现
# Item 10:在 constructors内阻止资源泄漏(resource leak)
利用constructor来避免资源泄露(最好还是使用智能指针的类比较好)
在构造新对象的过程中, 如果构造失败, 就可能会造成资源泄露
析构函数指挥析构已经构造完成的对象, 所以要考虑到在构造对象的时候,是否会发生异常。
所以要直接在构造函数里面对构造失败的异常进行捕获, 并且处理好这些异常, 对野指针进行delete。
把这些指针的删除, 全部包在一个clean up()的函数里面;
指向const的指针, 只能在初始化列表里面进行初始化, 这些对象的初始化过程中的异常, 可以放在一个private函数里面去进行,
不过最好还是使用auto_ptr之类的东西, 直接去管理类的成员数据, 比较方便一些
由于 C++不自动清理那些“构造期间抛出 exceptions”的对象,所以你必须设计你的 constructors,使它们在那种情况下亦能自我清理。
# Item 11:禁止异常(exceptions)流出 destructors之外
别让异常跑出destructor(dtor里面, 就不要再把异常往外抛了)
- 可以避免 terminate函数在exception传播过程的栈展开(stack-unwinding)机制中被调用;
- 它可以协助确保 destructors 完成其应该完成的所有事情, 程序不会中断。
- 也可以dtor里面也可以什么都不做, 就是为了程序能够顺利运行下去, 但是要确保这个异常不会真正影响程序本身
# Item 12:了解“抛出一个 exception”与“传递一个参数”或“调用一个虚函数”之间的差异
弄清楚, 抛出一个异常, 和 传递一个参数之间的区别
一个对象被抛出作为 exception时,总是会发生复制(copy), 但是若是以by value的方式捕获, throw和catch的时候, 都会发生一次临时变量的复制;
void passAndThrowWidget(){
static Widget localWidget;
cin >> localWidget;
throw localWidget; // 还是会对localWidget发生copy行为,然后再抛出
}
2
3
4
5
6
两种不同的throw语句:
catch(Widget &w){
...
throw; // 重新抛出这个exception,使它能继续传播
}
catch(Widget &w){
...
throw w; // 处理好之后, 继续往外传播这里catch到的exception
}
2
3
4
5
6
7
8
9
三种catch语句:
catch (Widget w) ...
catch (Wiget& w) ...
catch (const Widget& w) ...
2
3
execption和catch子句之间 不能发生隐式的类型转换:
void func(int value){
try{
if(someFunction()){
throw value;
}
}
catch(double d){ // 上面throw的是一个int类型, 这里是catch不到这个value的
...
}
}
2
3
4
5
6
7
8
9
10
但是,类型转换是能够发生在C++ exceptions的继承体系中的,可以理解为exception支持多态:

从有形指针抓换为无形指针的转换,catch是支持的:
catch(const void*){
...
}
2
3
# Item 13:以 Catch-by-reference 方式捕捉 exceptions
by value的局部变量复制问题, 并且,如果我们要继承exception定义自己的exception子类, 使用by value,虽然支持catch, 会发生slicing的问题, 也就是多态只能够针对地址类型才能够有效
by pointer 会有局部对象问题需要考虑,用起来考虑的问题比较多(catch之后要不要删除?是否返回了局部对象的地址?)
所以要以Catch-by-reference的方式捕获一个exception;
# Item 14:明智运用 exception specifications
明智地运用exception specification, 因为一旦使用, 就和async的使用一样, exception也会有内外传递的问题;
void func() throw(int); // 这里指定func()会抛出一个int类型的exception
// 继承exception定义自己的exception的时候,也是这种形势, 需要重新定义what的行为;
2
# Item 15:了解异常处理(exception handling)的成本
要清楚异常处理带来的成本;这些东西是C++本身就包括在里面的
粗略估计,如果使用 try 语句块,代码大约整体膨胀 5%~10%,执行速度亦大约下降这个数。这是在假设没有任何 exceptions 被抛出的情况下。此处我们所讨论的只是“代码中出现 try 语句块”的成本而已。
主要是时间和空间上面的成本;
需要讨论, C++ runtime时候, 编译, 连接的时候,对这些exceptions是怎么处理的?要使用profile工具针对特定程序做特定的性能分析;