3 异常
~~~~~~~

3.1 防止构造函数在存在异常时发生资源泄露
=========================================
   1. 如果你用对应的auto_ptr对象替代指针成员变量,就可以防止构造函数在存在异常时发生资源泄漏,你也不用手工在析构函数中释放资源,并且你还能象以前使用非const指针一样使用const指针,给其赋值。

3.2 理解"往catch语句传参数"与"往函数传递参数"的差别
====================================================
   1. 在函数中声明函数与在catch子句中声明参数几乎没什么差别,但
      无论通过传值捕获异常还是通过引用捕获异常,都将对传入catch的参数进行拷贝动作.
      当异常对象被拷贝时,拷贝操作是由对象的拷贝构造函数完成的.该拷贝构造函数是对象的 *静态类型* 所对应的拷贝构造函数,而不是对象的动态类型对应的拷贝构造函数.
 

  1. struct B 
  2.     virtual void say(){cout<<"this is "<<typeid(*this).name()<<endl;} 
  3. }; 
  4. struct D:public B 
  5. }; 
  6.  
  7. int main() 
  8.     try
  9.         D d; 
  10.         B& rb = d; 
  11.         rb.say();      //this is D1 
  12.         throw rb;      //这里抛出的是rb的拷贝,类型位B 
  13.     }catch(B& b) 
  14.     { 
  15.         b.say();       //this is B1 
  16.     } 


      在函数调用中不存在传递一个临时对象到一个非const引用类型的参数里,但是在异常中却被允许.
      函数的实参在传递给形参时会发生隐式类型转换,但catch子句在匹配异常类型时不会进行这样的转换.
   2. 异常是其它对象的拷贝,这个事实影响到你如何在catch块中再抛出一个异常。比如
 

  1. catch (Widget& w)                 // 捕获Widget异常 
  2. ...                             // 处理异常 
  3. throw;                          // 重新抛出异常,让它 
  4. }                                 // 继续传递 
  5. catch (Widget& w)                 // 捕获Widget异常 
  6. ...                             // 处理异常 
  7. throw w;                        // 传递被捕获异常的 
  8. }                                 // 拷贝 


       这两个catch块的差别在于第一个catch块中重新抛出的是当前捕获的异常,而第二个catch块中重新抛出的是当前捕获异常的一个新的拷贝。
   3. 不过在catch子句中进行异常匹配时可以进行两种类型转换。
      * 继承类与基类间的转换。
      * 允许从一个类型化指针(typed pointer)转变成无类型指针(所以带有const void* 指针的catch子句能捕获任何类型的指针类型异常)

3.3 使用引用异常
=================
   1. bad_alloc,bad_cast,bad_typeid,bad_exception都不是指向对象的指针,必须通过值或引用来捕获它们.
   2. 通过值捕获,它们抛出时系统将对异常对象拷贝两次,而且它会产生切片问题