###try语句块#
异常处理部分使用try语句块来处理异常。try语句块以try关键字开始,以一个或多个catch子句结束。try语句块中,使用throw抛出的异常被catch捕获并处理。
其语法规则为:
try{
program-statements
}catch(exception-declaration){
handler-statements
}catch(exception-declaration){
handler-statements
} //..
其中try语句块中的program-statements为正常语句块,exception-declaration为异常声明,handler-statements为捕获到异常后的异常处理语句。
###throw和catch#
C++里异常有两种
-
一种是CPU发起的(比如非法内存访问等),强行中断当前执行的程序,并由运行环境执行适当的应对代码。 但是在windows环境下,如vc++中,底层直接是用的Win32异常来实现的,所以从操作系统上来看,全是Win32异常,并不会被c++的try/catch捕获。
-
一种是C++里用throw语句抛出的异常,这个的结果只是一个单纯的跳转。
-
VC++如果编译的时候加/EHa参数 发生第一种异常的时候可以用C++的try/catch捕捉。
我们使用throw来抛出异常,用catch来捕获异常,如下举例:
double a,b;
while (cin<<a<<b){
try{
if (b != 0){
a=a/b;
cout<<a<<endl;
}else{
throw runtime_error("被0除");
}
}catch(runtime_error err){
cout<<err.what()<<"\nTry again?(y or n)"<<endl;
char c;
cin<<c;
if (!cin || c == 'n')
break;
}
}
-
**栈展开:**如果抛出的异常的函数调用语句位于一个try,则检查与该try关联的catch子句,如果找到了匹配的catch,就使用该catch来处理异常,否则如果该try包含在其他try块中,则继续检查与外层try匹配的catch子句,如果仍没有,则退出当前主调函数,继续在调用了该函数的其他函数中寻找,以此类推。如果最终没有catch匹配,则调用标准库函数terminate退出该程序;
-
**栈展开过程中对象被自动销毁:**块内局部对象会自动销毁,类类型对象会调用其析构函数;
-
**catch匹配类型:**允许throw非常量,catch捕获为常量;允许throw派生类,catch捕获为基类;数组被转换为指向数组(元素)类型的指针,函数被转换成直线该函数类型的指针;包括标准算数类型转换和类类型转换在内,其他所有转换规则都不能在匹配catch时使用;
-
**重新抛出:**当一个catch不能完整处理某个异常,可以将其重新抛出传递给另一个catch语句,重新抛出仍是一个throw语句,但是不包括任何表达式:throw;
-
**catch(...):**当使用catch来捕捉异常时,可以用catch(...)来捕获所有的异常。可以单独出现,也可以和其他的catch语句出现,如果catch(...)和其他的一起出现,则必须位于最后。
###C++中定义了一些标准异常:#
exception //最常见的问题
runtime_error //只有在运行时才能检测出的问题
range_error //运行时错误:生成计算结果超出了有意义的值域范围
overflow_error //运行时错误:计算上溢
underflow_error //运行时错误:计算下溢
logic_error //程序逻辑错误
domain_error //逻辑错误:参数对应的结果值不存在
invalid_argument //逻辑错误:无效参数
length_error //逻辑错误:试图创建一个超出该类型最大长度的对象
out_of_range //逻辑错误:使用一个超出有效范围的值
- exception是C++标准库异常类继承层次中的基类,定义于exception头文件,我们自定义的异常类也要继承自exception,它只报告异常的产生,不提供任何额外信息;
- 运行时错误由程序之外的事件造成,只有在运行时才能检测到;
- 逻辑类错误是程序本身不正常时造成,例如无效实参或超出范围的实参。
- 运行时错误和逻辑类错误定义于stdexcept头文件;
此外还有
- new头文件中定义的bad_alloc类型,用于报告new操作符不能正确分配内存的情形;
- type_info头文件中定义的bad_cast异常类型,dynamic_cast失败时,程序会抛出bad_cast异常类.