异常处理的目的
让一个函数在发现了自己无法处理,或不知道如何妥善的最优化的处理的错误时,抛出(throw)一个异常,然后它的(直接或者间接)调用者能够处理这个问题。 将问题检测和问题处理相分离。
在C语言的世界中,对错误的处理总是围绕着两种方法:一是使用整型的返回值标识错误;二是使用errno宏(可以简单的理解为一个全局整型变量)去记录错误。抛出异常是第三种更好的错误处理机制。
try catch
catch处理器的参数是引用,是throw出的异常对象,它并没有复制和创建新的异常对象。
catch处理器可以捕获异常并进行不彻底的异常处理,重新抛出异常。
try{ }语句块若没有抛出异常,try语句块执行完毕,忽略所有的catch处理器,继续往下执行。
try{ }语句块若抛出异常,说明try{ }语句块内调用了可能抛出异常的函数E,且函数E抛出了异常,
第一步:销毁函数E所有的局部变量。
第二步:暂停并跳出try语句块的执行流
第三步:逐一向下匹配catch处理器,遇到第一个该类或基类的异常引用,执行该catch处理器。
第四步:忽略剩下的所有catch处理器,紧接着执行最后一个catch处理下面的第一条语句。
如果没有匹配的处理器,会对try语句块所在函数进行堆栈展开。
堆栈展开
函数B是可能抛出异常的函数,函数A调用函数B,如果函数A没把函数B try并catch,那么函数A也变成了可能会抛出异常的函数。如果函数A把try{调用函数B的语句}catch(except &e),那么函数A是一个不会抛出异常的函数。
函数C抛出异常,销毁函数C的所有局部变量,如果函数B没有捕获C,销毁函数B的所有局部变量,如果调用函数B的函数A没有捕获异常,销毁函数B的所有局部变量,如果捕获了,则执行catch处理器。直至main函数,如果main函数也没捕获,则终止整个程序。
//Cat.h #include<iostream> class Cat{ private: int id; public: Cat(int id) { this->id = id; } ~Cat() { std::cout << id << " cat is destroied\n"; } };
#include<iostream> #include<stdexcept> #include"Cat.h" #include<cstdlib> using namespace std; void f3() { Cat c3(3); throw runtime_error("runtime_error in f3"); } void f2() { Cat c2(2); f3(); } void f1() { Cat c1(1); f2(); } int main() { Cat c0(0); try { f3(); } catch (runtime_error &e) { cout << e.what() << endl; } try { f1(); } catch (runtime_error &e) { cout << e.what() << endl; } system("pause"); }
3 cat is destroied
runtime_error in f3
3 cat is destroied
2 cat is destroied
1 cat is destroied
runtime_error in f3
请按任意键继续. . .