第17章 用于大型程序的工具(1)
17.1 异常处理
使用异常处理,程序中独立开发的各部分能够就程序执行期间出现的问题相互通信,并处理这些问题。程序的一个部分能够检测出本部分无法解决的问题,这个问题检测部分可以将问题传递给准备处理问题的其他部分。
通过异常我们能够将问题的检测和问题的解决分离,这样程序的问题检测部分可以不必了解如何处理问题。
17.1.1 抛出类类型的异常
异常是通过抛出(throw)对象而引发(raise)的。该对象的类型决定应该激活哪个处理代码。被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那个。
异常以类似于将实参传递给函数的方式抛出和捕获。异常可以是可传给非引用形参的任意类型的对象,这意味着必须能够复制该类型的对象。
执行throw的时候,不会执行跟在throw后面的语句,而是将控制从throw转移到匹配的catch,该catch可以是同一函数中局部的catch,也可以在直接或间接调用发生异常的函数的另一个函数中。控制从一个地方传递到另一个地方,这有两个重要含义:
(1)沿着调用链的函数提早退出。
(2)一般而言,在处理异常的时候,抛出异常的块中的局部存储不存在了。
因为在处理异常的时候会释放局部存储,所以被抛出的对象就不能再局部存储,而是用throw表达式初始化一个称为异常对象(exception object)的特殊对象。这个对象由throw创建,并被初始化为被抛出的表达式的副本。异常对象将传给对应的catch,并且在完全处理了异常之后撤销。
异常对象通过复制被抛出表达式的结果创建,该结果必须是可以复制的类型。
1. 异常对象与继承
当抛出一个表达式的时候,被抛出对象的静态编译时类型将决定异常对象的类型。
2. 异常与指针
用抛出表达式抛出静态类型时,比较麻烦的一种情况是,在抛出中对指针解引用。对指针解引用的结果是一个对象,其类型与指针的类型匹配。如果指针指向继承层次中的一种类型,指针所指对象的类型就有可能与指针的类型不同。无论对象的实际类型是什么,异常对象的类型都与指针的静态类型相匹配。如果该指针是一个指向派生类对象的基类类型指针,则那个对象将被分割,只抛出基类部分。
抛出指向局部对象的指针总是错误的,其理由由与函数返回指向局部对象的指针是错误的一样。抛出指针的时候,必须确定进入处理代码时指针所指向的对象存在。
如果抛出指向局部对象的指针,而且处理代码在另一函数中,则执行处理代码时指针所指向的对象将不再存在。即使处理代码在同一函数中,也必须确信指针所指向的对象在catch处存在。如果指针指向某个在catch之前退出的块中的对象,那么,将在catch之前撤销该局部对象。
抛出指针通常是个坏主意:抛出指针要求在对应处理代码存在的任意地方存在指针所指向的对象。
void Method1(){
try
{
throw range_error("error~");
}
catch(exception &e)
{
cout<<e.what()<<endl;
}
}
void Method1(){
try
{
throw range_error("error~");
}
catch(exception &e)
{
cout<<e.what()<<endl;
}
}Method1(); //error~
摘自 xufei96的专栏
补充:软件开发 , C++ ,