自测练习
13.1 列出五个常见的异常例子。
13.2 说明异常处理方法不能用于传统程序控制的原因。
13.3 为什么异常适合处理库函数产生的错误
13. 4 什么是“资源泄漏”
13.5 如果try块中不抛出异常,try块执行完毕之后控制转到哪里
13.6 如果在try块之外抛出异常,会发生什么情况
13.7 说明使用catch(...)的主要优点和主要缺点。
13.8 如果没有匹配所抛出对象类型的catch处理器,会发生什么情况
13.9 如果有多个匹配所抛出对象类型的catch处理器,会发生什么情况
13.10 为什么程序员要指定基类类型为catch处理器类型,然后抛出派生类类型的对象
13.11 catch处理器如何编写成处理相关错误类型而不用异常类之间的继承
13.12 catch处理器中用哪种指针类型捕获任何指针类型的所有异常
13.13 假设有准确匹配异常对象类型的catch处理器,什么情况下该异常对象类型会执行不同的catch处理器
13.14 抛出异常是否一定终止程序
13. 15 catch处理器抛出异常时会发生什么情况
13. 16 throw;语句有什么用
13. 17 程序员如何限制函数可以抛出的异常类型
13. 18 如果函数抛出函数异常指定中不允许的异常类型,会发生什么情况
13.19 try块抛出异常时,其中已经构造的自动对象发生什么情况
自测练习答案
13. 1 内存不足以满足new的请求、数组下标超界、运算溢出、除数为0、无效函数参数。
13.2 (a)异常处理是用于处理不常发生的情况,通常在程序准备终止时使用。因此,C++编译器的编写人员不像对正常应用程序代码一样对其实现最优化性能。(b)使用传统控制结构的控制流通常比使用异常更清晰更有效。(c)另一危险是堆栈解退,异常发生之前分配的资源可能无法释放。(d)这些“增加的”异常可能打乱真正的错误类型异常。程序员更难跟踪异常种类。例如,程序处理大量异常时,无法确定catch(...)捕获的是什么异常。
13.3 库函数很难满足用户特殊需求的错误处理。
13. 4 退出程序会使其他程序无法使用其资源,从而造成资源泄漏。
13.5 忽略该时块的异常处理器(catch块中),程序在最后一个catch块后重新执行。
13.6 try块之外抛出的异常会使程序终止。
13.7 catch(…)能捕获时块中抛出的所有错误。其优点是可以捕获所有错误,缺点是catch没有参数,无法引用抛出的所有错误中的信息,无法知道错误原因。
13.8 这时匹配搜索会继续到外面一层try块。这个过程一直继续,也许最终还是没有任何匹配的异常处理器。这时调用terminate(默认调用abort终止程序)。可以用set_terminate的参数提供另一terminate函数。
13.9 执行时块后面第一个匹配的异常处理器。
13.10 这样可以很好地捕获相关类型的异常。
13. 11 可以用一个异常类和catch处理器处理一组异常。发生每个异常时,可以生成具有不同private数据的异常对象。catch处理器通过检查private数据区分异常的类型。
13. 12 void*。
13.13 要求标准转换的处理器可能出现在具有准确匹配的处理器之前。
13. 14 不一定,但它终止抛出异常的块。
13. 15 异常由导致异常的catch处理器所在try块(如果有)的相关catch处理器(如果有)处理。
13.16 再抛出异常。
13.17 提供从函数可抛出异常类型的异常指定表。
13.18 调用函数unexpected。
13.19 通过堆栈解退过程,调用每个对象的析构函数。
练 习
13. 20 列出文中所列的程序中发生的各种异常条件,尽量多列几个异常条件。对每个异常条件,简单描述程序如何用本章介绍的异常处理方法处理这个异常。典型的异常有:内存不足以满足new的请求、数组下标超界、运算溢出、除数为0、无效函数参数。
13.21 什么情况下程序员在定义处理器捕获对象类型时不提供参数名
13. 22 程序包含下列语句:
throw;
这种语句通常出现在什么地方如果出现在其他地方,会发生什么情况
13.23 下列语句通常出现在什么情况下
catch(...){throw};
13.24 比较异常处理与各种其他错误处理方法。
13.25 列出异常处理比传统错误处理方法的优势。
13.26 说明为什么不宜用异常作为程序控制的替换方法。
13.27 说明处理相关异常的方法。
13.28 到本章为止,我们发现处理构造函数所发现的错误比较麻烦。异常处理提供了处理这种错误更好的办法。考虑String类的构造函数。这个构造函数用new取得自由空问。假设new操作失败,说明不用异常时如何处理这种情况,讨论关键点。说明使用异常时如何处理这种情况。说明异常处理的优点在哪里。
13.29 假设程序抛出异常,开始执行相应的异常处理器。再假设异常处理器本身抛出相同的异常。这样会生成无穷递归吗编写一个C++程序,测试得出的结论。
13.30 用继承方法生成异常基类和各种派生类。然后显示指定基类的catch处理器能捕获派生类的异常。
13.31 列出返回double或int的条件异常。提供一个int catch处理器和一个double catch处理器。
说明不管返回double或int,都只执行double catch处理器。
13.32 编写一个C++程序,产生和处理内存溢出错误。程序通过运算符new循环请求生成动态存储空间。
13.33 编写一个C++程序列出调用块中构造的所有对象的析构函数之后再从块中抛出异常。
13.34 编写一个C++程序,演示只调用发生异常之前构造的成员对象的成员对象析构函数。
13.35 编写一个C++程序,演示catch(...)如何捕获任何异常。
13.36 编写一个C++程序,表明异常处理器的顺序很重要。执行的是第一个匹配的异常处理器。编译和运行程序,显示执行不同异常处理器时的不同效果。
13.37 编写一个C++程序,表明构造函数传递构造失败信息给try块后面的异常处理器。
13.38 编写一个C++程序,用异常类的多重继承层次生成要考虑异常处理器顺序的情况。
13.39 用setjmp/Iongjmp时,程序可以立即从深层嵌套函数调用将控制转移到错误程序。但由于堆栈解退,不能调用嵌套函数调用期间生成的自动对象的析构函数。编写一个C++程序,演示的确没有调用嵌套函数调用期间生成的自动对象的析构函数。
13.40 编写一个C++程序,演示再抛出异常。
13.41 编写一个C++程序,用set_unexpected对unexpected设置用户自定义函数,再次用set_unexpected,然后将unexpected复位为原先的函数。编写一个C++程序,测试set_terminate和terminate。
13.42 编写一个C++程序,显示本身有时块的函数不必捕获try块中产生的每个错误。有些错误留给外层范围处理。
13.43 编写一个C++程序,从深层嵌套函数调用抛出错误,并让调用链所在try块后面的catch处理器捕获这个异常。