18.1.1 抛出异常
- 栈展开
- 栈展开过程中对象被自动销毁
- 析构函数与异常——WARING 在栈展开的过程中,运行类类型的局部对象的析构函数,因为这些析构函数是自动执行的,所以他们不应该抛出异常。一旦在栈展开的过程中析构函数抛出了异常,并且析构函数自身没能捕获到该异常,则被程序终止。
- 异常对象——是一种特殊的对象,编译器使用异常抛出表达式来对异常对象进行拷贝初始化。因此throw语句中的表达式必须拥有完全类型。而且如果表达式是类类型的话,则相应的类必须含有一个可以访问的析构函数和一个可访问的拷贝或移动构造函数。如果该表达式是数组类型或函数类型,则表达式将被转换成与之对应的指针类型。异常对象位于编译器管理的空间中,编译器确保无论最终调用的是哪个catch字句都能访问该空间,当异常处理完毕后,异常对象被销毁。如我们所知,当一个异常被抛出时, 沿着调用链的块将依次退出直至找到与异常匹配的处理代码。如果退出某个块,则同时释放块中局部对象使用的内存,因此,抛出一个指向局部对象的指针几乎肯定是一种错误的行为。出于同样的原因,从函数中返回指向局部对象的指针也是错误的。如果指针所指的对象位于某个块中,而该块在catch语句之前已经退出了,则意味着在执行catch语句之前局部对象已经被销毁了。当我们抛出一条表达式时,该表达式的静态编译时类型决定了异常对象的类型。必须牢记这一点,因为很多情况下抛出的表达式类型来自某个继承体系。如果一条throw表达式解引用一个基类指针,而该指针指向的是派生类对象,则抛出的对象将被切掉一部分,只有基类部分被抛出。
18.1.2 捕获异常
- catch 字句(catch clause)中的异常声明(exception declaration)看起来像是只包含一个形参的函数形参列表。像在形参列表中一样,如果catch 无须访问抛出的表达式的话,则可以忽略捕获的形参名字。声明的类型决定了处理代码所能捕获的异常类型。此类型必须是完全类型,可以是左值引用,但不能是右值引用。如果catch 的参数是基类的引用,则该参数将以常规方式绑定到异常对象上。需要注意的一点是。异常声明的静态类型决定catch语句所能执行的操作,如果在catch形参中使用的是基类类型,则catch块中无法使用其派生类持有的任何成员。如果catch 接受的异常与某个继承体系有关,则最好该catch的参数定义成引用类型。
- 查找匹配的处理代码—— 要求异常的类型和catch声明的类型是精确匹配的。
- 允许从非常量向常量转换,也就是说,一条非常量对象的throw 语句可以匹配一个接受常量引用的catch语句
- 允许派生类向基类的类型转换
- 数组被转换成指向数组(元素)类型的指针,函数被转换成指向该函数类型的指针。
Note: 如果在多个catch 语句的类型之间存在着继承关系,则我们应该把继承链最低端的类(most derived type)放在前面。而将继承链最顶端的类(least derived type)放在后面。
- 重新抛出——有时,一个单独的catch 语句不能完整地处理某个异常。需要调用链更上一层的函数接着处理异常,通过重新抛出(rethrowing)的操作将异常转递给另外一个catch语句处理, 例如:throw; 注意throw不能跟任何表达式。234 接着写