一,什么是异常
当程序在运行过程中,函数中出现了自己无法处理的错误时抛出异常。让函数的调用者直接或间接处理这个错误。
二,异常编写形式
c++的异常包括下面的三个部分:
1.throw子句:throw子句用于抛出异常,被抛出的异常可以是C++的内置类型(例如: throw int(1);),也可以是自定义类型。
2.catch子句:每个catch子句都代表着一种异常的处理。catch子 句用于处理特定类型的异常。
3.try区段:这个区段中包含了可能发生异常的代码,在发生了异常之后,需要通过throw抛出。
try-catch语句形式如下:
try
{
//do something
//包含可能抛出异常的语句
}
catch(类型名 [形参名]) // 捕获特定类型的异常
{
//处理1
}
catch(类型名 [形参名]) // 捕获特定类型的异常
{
//处理2
}
catch(...) //表示捕获所有类型的异常,通常是捕获未知类型错误。
{
//处理3
}
栗子:
try
{
char*p = new char[0x7fffffff];
}
catch (exception e)
{
cout << e.what() << endl;
}
catch(...)
{
cout<<"未知异常"<<endl;
}
C++库中自带了一个异常类:
详情见链接:
http://www.cplusplus.com/reference/exception/exception/?kw=exception
三,栈展开
抛出异常的时候,将暂停当前函数的执行,开始查找对应的匹配catch子句。当一个exception被抛出的时候,控制权会从函数调用中释放出来,并需找一个可以处理的catch子句。对于一个抛出异常的try区段,程序会先检查与该try区段关联的catch子句,如果找到了匹配的catch子句,就使用这个catch子句处理这个异常。否则,如果这个try区段嵌套在其他try区段中,则继续检查与外层try匹配的catch子句。如果仍然没有找到匹配的catch子句,则退出当前这个主调函数,并在调用了刚刚退出的这个函数的其他函数中寻找。这个过程就是所谓的栈展开,栈展开会沿着嵌套函数的调用链不断查找,知道找到了已抛出的异常匹配的catch子句。如果在最后还是没有找到对应的catch子句的话,则退出主函数后查找过程终止,程序调用标准函数库的terminate()函数,终止该程序的执行。
异常捕获匹配规则
异常对象的类型与catch说明符的类型必须完全匹配。
以下情况例外:
1,从非const到const对象的转换。
2,从派生类型到基类类型的转换。
3,将数组类型转换成指向数组类型的指针 ,将函数类型转换成指向函数类型的指针。
注意:
1. 构造函数完成对象的构造和初始化,需要保证不要在构造函数中抛出异常,否则可能导致对象不完整或没有完全初始化。
2. 析构函数主要完成资源的清理,需要保证不要在析构函数内抛出异常,否则可能导致资源泄漏(内存泄漏、句柄未关闭等)
四,C++异常的优缺点:
优点:
1.可以清晰的展示出错误原因,不像返回错误码那么模糊 。
2.许多第三方库使用异常,因此容易与这些结合使用 。
3.在测试框架里使用比较方便 。
缺点:
1.会打断执行流,函数有可能不在该返回的地方返回,这样使得代码的管理和调试困难 。
2.异常安全要使用RAII和不同编码实践。加大了代码量,需要大量的支持。