第17章 用于大型程序的工具(2)
17.1.2 栈展开
如果对抛出异常的函数的调用是在try块中,则检查与该try相关的catch子句。如果找到匹配的catch,就处理异常;如果找不到匹配的catch,调用函数也退出,并且继续在调用这个函数的函数中查找。这个过程,称之为栈展开(stack unwinding)。
1. 为局部对象调用析构函数
栈展开期间,释放局部对象所用的内存并运行类类型局部对象的析构函数。
2. 析构函数应该从不抛出异常
在为某个异常进行栈展开的时候,析构函数如果又抛出自己的未经处理的另一个异常,将会掉值调用标准库的terminate函数。一般而言,terminate函数将调用abort函数,强制从整个程序非正常退出。
3. 异常与构造函数
与析构函数不同,构造函数内部所做的事情经常会抛出异常。如果在构造函数对象的时候发生异常,则该对象可能只是部分被构造,它的一些成员可能已经初始化,而另一些成员在异常发生之前还没有初始化。即使对象只是部分被构造了,也要保证将会适当地撤销已构造的成员。
4. 未捕获的异常终止程序
如果找不到匹配的catch,程序就调用库函数terminate。
17.1.3 捕获异常
catch子句(catch clause)中的异常说明符(exception specifier)看起来像只包含一个形参的形参表,异常说明符是在其后跟一个(可选)形参名的类型名。
说明符的类型据诶的那个可处理代码能够捕获的异常种类。种类必须是完全类型,即必须是内置类型或者是已经定义的程序员自定义类型。类型的前向声明不行。
1. 查找匹配的处理代码
在查找匹配的catch期间,找到的catch不必是与异常最匹配的那个catch,相反,将选中第一个找到的可以处理该异常的catch。因此在catch子句列表中,最特殊的catch必须最先出现。
允许从非const到const的转换。
允许从派生类型到基类类型的转换。
将数组转换为指向数组类型的指针,将函数转换为指向函数类型的适当指针。
2. 异常说明符
进入catch的时候,用异常对象初始化catch的形参。像函数形参一样,异常说明符类型可以是引用。异常对象本身是被抛出对象的副本。是否再次将异常对象复制到catch位置取决于异常说明符类型。
如果说明符不是引用,就将异常对象复制到catch形参中,catch操作异常对象的副本,对形参所做的任何改变都只作用域副本,不会作用于异常对象本身。如果说明符是引用,则像引用形参一样,不存在单独的catch对象,catch形参只是异常对象的另一名字。对catch形参所做的改变作用于异常对象。
3. 异常说明符与继承
像形参声明一样,基类的异常说明符可以用于捕获派生类型的异常对象,而且,异常说明符的静态类型决定catch子句可以执行的动作。如果被抛出的异常对象是派生类类型的,但由接受基类类型的catch处理,那么,catch不能使用派生类特有的任何成员。
通常,如果catch子句处理因继承而相关的类型的异常,它就应该将自己的形参定义为引用。
4. catch子句的次序必须反映类型层次
将异常类型组织成类层次的时候,用户可以选择应用程序处理异常的粒度级别。
因为catch子句按出现次序匹配,所以使用来自继承层次的程序必须将它们的catch子句排序,以便派生类型的处理代码出现在其基类类型的catch之前。
带有因继承而相关的类型的多个catch子句,必须从最低派生类型到最高派生类型排序。
补充:软件开发 , C++ ,