16.2 异常机制
除了人为防错外,还可以使用异常机制来处理错误,异常机制提供了将控制权从程序的一部分转移到另一部分的方法,对异常处理主要由以下3部分组成。
❑使用try块。
❑异常发生时,使用throw抛出。
❑使用catch块捕获异常。
如示例代码16.3所示。
代码16.3 异常处理范例ExceptionHandling
<———————————-文件名:example1603.cpp———————————————> 01 #include<iostream> 02 #include<cmath>//使用sqrt函数要包含的头文件 03 using namespace std; 04 double calc() 05 { 06 cout<<"请输入1个不小于0的数:"<<endl; 07 double num=-1; 08 cin>>num; 09 if(!cin. good())//输入失败 10 { 11 cin. clear();//清除流状态字 12 cin. sync();//清空流缓冲区 13 throw"错误,输入的不是数字";//抛出字符串型异常 14 } 15 if(num<0)//如果num<0,或输入不成功,则抛出字符串类型s 16 throw"错误,请输入1个不小于0的数字";//抛出字符串型异常 17 return sqrt(num); 18 } 19 int main() 20 { 21 double res=0; 22 while(true) 23 { 24 try//使用try块标记可能发生异常的代码块 25 { 26 res=calc();//正常的函数调用,如果异常发生,将被抛出 27 } 28 catch(const char*s)//捕获try块中抛出的异常 29 { 30 cout<<s<<endl; 31 continue;//重新循环 32 } 33 cout<<res<<endl;//没有异常发生,输出结果 34 break;//跳出循环 35 } 36 return 0; 37 }
输出结果如下所示。
请输入1个不小于0的数: G(用户输入) 错误,输入的不是数字 请输入1个不小于0的数: -3(用户输入) 错误,请输入1个不小于0的数字 请输入1个不小于0的数: 5(用户输入) 2.23607
【代码解析】代码提示用户输入一个非负数,计算其平方根并输出。在用户输入时,输入的字符可能不是数字,也有可能输入一个负数,而求平方根要求操作数非负,因此,在calc函数中对可能出现的错误进行了throw处理,代码第13和16行的语句将标记错误信息的字符串“错误,输入的不是数字”和“错误,请输入1个不小于0的数字”抛出。当异常处理程序(即catch块)捕获异常后,对字符型异常进行显式处理。
try块表示了发生异常的代码块,try块可以和一个或多个catch块(异常处理程序,Exception Handler)搭配使用,catch语句也有参数,其参数即是throw语句抛出异常的类型,代码16.3中抛出的两个异常都是字符串,实际上异常可以是其他类型,如int和double等内置类型,设置还可以是自定义的类对象,这在稍后会有所介绍,举抛出int型异常为例,catch语句头如下所示。
catch(int num) { …… }
如果try块调用的函数中有可能抛出多种类型的异常,便需要多个catch块,每个catch块捕获一种类型的异常,进行相应的处理。注意,只要在try块中抛出的异常才会被catch块捕获,代码16.3中,如果在try块外部调用calc函数,catch块无法对异常进行处理。
注意
在VC6中,代码16.3应采用release模式编译。
16.2.1 关键字throw
throw关键字表示抛出异常,这实际上是跳转语句,当程序执行到throw语句抛出异常时,直接跳出当前try块,执行对应的catch块,如果未定义捕获该异常类型的catch块时,默认的terminate函数将被执行,稍后会有相关介绍。
说明
如此看来,throw操作实际上是将本函数中无法处理的错误或异常抛出到更高级别的代码域中进行处理。
C++提供了异常规范说明机制以显式说明函数所抛出的异常,方便使用者对程序进行处理,当然,异常规范说明不是必须的,在代码16.3中便没有进行异常规范说明。
异常规范说明使用了关键字throw,函数可能抛出的所有可能异常的类型应该都被写在throw之后的括号内。“throw(类型列表)”形式的异常规范说明应写在函数参数列表的后面,如对代码16.3中定义的calc函数可添加如下异常规范说明。
double calc()throw(const char*) { …… }如果需要抛出多种类型的异常,则需要将抛出的类型都写在参数列表中,如下所示。 double calc()throw(const char*,int) { …… }
上述代码明确告诉函数调用者,calc函数有可能抛出字符串型的异常,也可能抛出int型的异常,如果函数所抛出的异常没有列在异常规范说明中,系统将自动调用函数unexpected,稍后会有对此函数的介绍。
注意
“throw()”表示函数不会抛出任何异常;当省略异常规范说明时,表示函数可能抛出任何类型的异常。