C++异常处理
C++异常处理
抛出异常
在C++语言中,通过抛出一条表达式来引发一个异常。被抛出的表达式的类型以及当前的调用链共同决定了哪段处理代码将被用来处理该异常。
栈展开
当抛出一个异常后,程序暂停当前函数的执行过程并立即开始寻找与异常匹配的catch子句,如果没找到匹配的catch子句,则继续检查与外层try匹配的catch子句,直到找到了与异常匹配的catch句子为止。如果仍然没有找到匹配的catch子句,则退出当前主调函数,继续在调用当前函数的其他函数中继续寻找。上述这个过程被称为栈展开过程。
栈展开过程沿着嵌套函数的调用链不断查找,直到找到了与异常匹配的catch句子为止,或者也可能一直没找到匹配的catch,则程序将调用标准库函数terminate终止当前的程序,退出主函数后查找过程终止。
栈展开过程中对象被自动销毁
如果在栈展开过程中退出了某个块,编译器将负责确保在这个块中创建的对象能被正确销毁。
如果异常发生在构造函数中,即使某个对象只构造了一部分,我们也要确保已构造的成员能被正确地销毁。(类似的,数组或标准库容器的元素初始化过程中)
析构函数与异常
在栈展开的过程中,运行类类型的局部对象的析构函数。因为这些析构函数是自动执行的,所以它们不应该抛出异常,如果要抛出异常,则应该在析构函数内部得到处理。一旦在栈展开的过程中析构函数抛出了异常,并且析构函数自身没能捕获到该异常,则程序将被终止。
异常对象
异常对象是一种特殊对象,编译器使用异常抛出表达式来对异常对象进行拷贝初始化。因此throw语句中的表达式必须拥有完全类型。
异常对象位于编译器管理的空间中,编译器确保无论最终调用的是哪个catch子句都能访问该空间。
捕获异常
有时候一个单独的catch语句不能完整地处理某个异常,一条catch语句通过重新抛出的操作将异常传递给另外一个catch语句。
很多时候,catch语句会改变其参数的内容。只有当catch异常声明是引用类型时我们对参数所做的改变才会被保留并继续传播:
catch (my_error &eObj) {
//引用类型
eObj.status = errCodes::serverErr; //修改了异常对象
throw;
} catch (other_error eObj) {
//非引用类型
eObj.status = errCodes::badErr;
throw;
}