[More Effective C++ 学习笔记]异常

<异常>

       条款9:利用destructors避免泄露资源

       在函数中,可以将资源封装在局部对象中,通常便可以在exceptions出现时避免泄露资源。是因为局部对象总是会在函数结束时被析构,不论函数如何结束,但唯一例外的就是调用longjmp而结束。

 

       条款10:在constructors内阻止资源泄露(resource leak)

       C++只会析构已构造完成的对象。对象只有在其constructor执行完毕才算是完全构造妥当。

  面对尚未完全构造好的对象,为什么C++拒绝调用其析构函数?是因为若析构函数被调用于一个尚未完全的构造好的对象身上,那么这个析构函数如何知道构造函数现在构造了那些资源?若添加变量来统计资料的构造程度,将造成效率的降低。

 

       条款11:禁止异常(exceptions)流出destructors之外

       在两种情况下,析构函数会被调用:

  1. 当对象正常状态下被销毁,也就是当它离开了它的生存空间(scope)或是被明白地给予删除;
  2. 当对象呗exception处理机制销毁,即exception传播过程中的stack-unwinding(栈辗转开锁)机制。

 

  有两个理由支持我们全力阻止exceptions传出destructors之外:

  1. 它可以避免terminate函数在exception传播过程的栈辗转开解机制中被调用;
  2. 它可以协助确保destructors完成其应该完成的所有事情。

 

  条款12:了解抛出一个exception与传递一个参数或调用一个虚函数之间的差异

  函数参数和exceptions的传递方式有三种:by value、by reference、by pointer。但是需要注意两者的不同,是因为如果你调用一个函数,控制权最终会回到调用端(除非失败以至于无法返回),但是当你抛出一个exception,控制权不会再回到抛出端。

 

  exceptions与catch字句匹配的过程中,仅有两种转换可以发生:

  1. 继承架构中的类转换;
  2. 从一个有型指针转换为无型指针。所以一个针对const void *指针而设计的catch子句,可以捕捉任何指针型别的exception。

 

  传递对象到函数或是以对象调用虚函数和将对象抛出成为一个exception之间的差异:

  1. exception objects总是会被拷贝:如果以by value方式捕捉,它们甚至被拷贝两次;
  2. 被抛出成为exceptions的对象,其被允许的型别转换动作要比被传递到函数去的对象少;
  3. catch子句以其出现于源代码的次序被编译器检验比对,齐总第一个匹配成功者便获得执行。

 

  条款13:以by reference方式捕捉exceptions

  catch-by-pointer方式是唯一在搬移异常相关信息时不需要拷贝对象的一种做法。它有两种做法:

  1. 抛出局部对象的指针,即从栈上分配的内存空间。但是该对象离开作用域将被析构,因此需要让异常对象在离开作用域后仍然存在,即全局对象或静态对象。
  2. 抛出一个新的指向堆的对象。但是需要考虑什么时候释放内存,以防止内存泄露。

 

  catch-by-value方式:当异常对象被抛出时,就的拷贝两次。同时它可能印发对象切割问题。因为derived class exception objects被捕捉并被视为base class exceptions者,将失去其派生成分(参考《深入探索C++对象模型》)。

 

  catch-by-reference方式:它不像catch-by-pointer,不会发送对象删除问题,因此也就不难捕捉标准的异常;它也不想catch-by-value,没有切割问题,而且异常只会被拷贝一次。

 

       条款14:明智运用exception specifications

       如果函数抛出一个未列于其exception specification的exception,这个错误将会在运行期被检测出来,于是特殊函数unexpected会被自动调用。其中,unexpected函数的缺省行为是调用terminate函数,而terminate函数的缺省行为是调用abort函数,因此程序如果违反exception specification,缺省结果就是程序被中断。

 

       避免踏上unexpected之路的方法:

  1. 避免将exception specification放在需要型别自变量的templates身上;
  2. 如果函数A内调用了函数B,而函数B屋exception specification,那么A函数本身也不要设定exception specification;
  3. 处理系统可能抛出的exceptions。

 

  C++允许你以不同型别的exceptions取代非预期的exceptions。

 

       条款15:了解异常处理(exception handling)的成本

       为了能够在运行期处理exceptions,程序必须做大量的簿记工作。在每一个执行点,它们必须能够确认如果发送exception,哪些对象需要析构;它们必须在每一个try语句块的进入点和离开点做记号;针对每个try语句块它们必须记录对应的catch子句以及能够处理的exceptions型别。

 

       PS. 这里只是一个大体,如果想要了解更多的知识或者更好的运用,需要看《More effective C++》一书中对异常的具体条款描述。

你可能感兴趣的:(effective)