一、异常的概念及使用
1.1 异常的概念
- 异常处理机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并做出相应的处理,异常使得我们能够将问题的检测与解决问题的过程分开。程序的一部分负责检测问题的出现,然后解决问题的任务传递给程序的另一部分,检测环节无须知道问题的处理模块的所有细节。
- C 语言主要通过错误码的形式处理错误,错误码本质就是对错误信息进行分类编号,拿到错误码还要去查询错误信息,比较麻烦。异常时抛出一个对象,这个对象可以解释更全面的信息。
1.2 异常的抛出和捕获
- 当我们遇到异常时,我们可以使用
throw 将这个异常信息抛出,这个被抛出的信息会随着我们的调用链一层一层的进行 catch 捕获,如果遇到相匹配的就被成功捕获。
- 我们抛出什么类型的异常,捕获异常就要用相应类型的对象来接受,才算捕捉成功。
- 当我们抛出异常时,编译器就会寻找与之相匹配的
catch 语句,这中间会跳过 throw 和与之对应 catch 中间的所有语句(所以要加之小心)。
- 抛出异常后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个局部对象,所以会生成一个拷贝对象,这个拷贝的对象会在 catch 子句后销毁。
1.3 栈展开
- 抛出异常后,程序暂停当前函数的执行,开始寻找与之匹配的 catch 子句。首先检查 throw 本身是否在 try 内部,如果是则再查找匹配的 catch 语句,如果有匹配的,则跳到 catch 的地方进行处理。
- 如果当前函数中没有 try/catch 子句,或者有 try/catch 子句但是类型不匹配,则退出当前函数,继续在外层调用函数链中查找,上述查找的 catch 过程被称为栈展开。
- 如果到达 main 函数,依旧没有找到匹配的 catch 子句,程序会调用标准库的
terminate 函数终止程序。
- 如果找到匹配的 catch 子句处理后,catch 子句代码会继续执行。
double divide(int a, int b) {
try {
if (b == 0) {
string s("divide by zero condition");
throw s;
} else {
return (double)a / (double)b;
}
} catch (int errid1) {
cout << errid1 << endl;
}
}
void func() {
int a, b;
cin >> a >> b;
try {
divide(a, b);
} ( * errid2) {
cout << errid2 << endl;
}
cout << << endl;
}
{
{
();
} (string& s) {
cout << s << endl;
}
;
}