3 异常
~~~~~~~
3.1 防止构造函数在存在异常时发生资源泄露
=========================================
1. 如果你用对应的auto_ptr对象替代指针成员变量,就可以防止构造函数在存在异常时发生资源泄漏,你也不用手工在析构函数中释放资源,并且你还能象以前使用非const指针一样使用const指针,给其赋值。
3.2 理解"往catch语句传参数"与"往函数传递参数"的差别
====================================================
1. 在函数中声明函数与在catch子句中声明参数几乎没什么差别,但
无论通过传值捕获异常还是通过引用捕获异常,都将对传入catch的参数进行拷贝动作.
当异常对象被拷贝时,拷贝操作是由对象的拷贝构造函数完成的.该拷贝构造函数是对象的 *静态类型* 所对应的拷贝构造函数,而不是对象的动态类型对应的拷贝构造函数.
- struct B
- {
- virtual void say(){cout<<"this is "<<typeid(*this).name()<<endl;}
- };
- struct D:public B
- {
- };
- int main()
- {
- try{
- D d;
- B& rb = d;
- rb.say(); //this is D1
- throw rb; //这里抛出的是rb的拷贝,类型位B
- }catch(B& b)
- {
- b.say(); //this is B1
- }
- }
在函数调用中不存在传递一个临时对象到一个非const引用类型的参数里,但是在异常中却被允许.
函数的实参在传递给形参时会发生隐式类型转换,但catch子句在匹配异常类型时不会进行这样的转换.
2. 异常是其它对象的拷贝,这个事实影响到你如何在catch块中再抛出一个异常。比如
- catch (Widget& w) // 捕获Widget异常
- {
- ... // 处理异常
- throw; // 重新抛出异常,让它
- } // 继续传递
- catch (Widget& w) // 捕获Widget异常
- {
- ... // 处理异常
- throw w; // 传递被捕获异常的
- } // 拷贝
这两个catch块的差别在于第一个catch块中重新抛出的是当前捕获的异常,而第二个catch块中重新抛出的是当前捕获异常的一个新的拷贝。
3. 不过在catch子句中进行异常匹配时可以进行两种类型转换。
* 继承类与基类间的转换。
* 允许从一个类型化指针(typed pointer)转变成无类型指针(所以带有const void* 指针的catch子句能捕获任何类型的指针类型异常)
3.3 使用引用异常
=================
1. bad_alloc,bad_cast,bad_typeid,bad_exception都不是指向对象的指针,必须通过值或引用来捕获它们.
2. 通过值捕获,它们抛出时系统将对异常对象拷贝两次,而且它会产生切片问题