异常处理
- 在程序运行时,可能会遇到各种异常问题,例如:两数相除时除数为0,数组越界,内存空间不够,无法打开输入文件而不能读取数据,输入数据的类型有错等。如果程序没有对这些问题进行防范,导致程序出错,系统就只能终止程序的运行。因此,在设计程序时,应当分析程序运行时可能出现的各种意外情况,并分别指定相应的处理方法,增强系统的容错能力,这就是程序异常处理的作用。
- 在小型程序中,异常处理方法比较简单,通过判别并显示出错信息就能解决。而在大型软件中,函数之间的耦合度非常低,函数之间的互相调用以及异常处理会让程序变得非常复杂和庞大。因此,C++中采用的方法是逐级传送:函数可能会发现自己无法处理的错误,这时它可以抛出一个异常,希望调用者可以直接或间接处理这个错误。如果调用者也不能直接处理这个错误,可以继续传给上一级的调用者。相对于传统错误处理技术,异常处理把错误和处理分开,简化程序错误处理代码,为程序健壮性提供一个标准监测机制。程序员在编写程序时首先假设不会产生任何异常,将全部代码编写完成后,再利用C++异常处理机制,添加用于处理异常情况的语句。
- 简单的说,异常处理的基本思想是:让一个函数在发现了自己无法处理的错误时抛出一个异常,然后让它的(直接或间接)调用者能够处理这个问题。C++异常处理机制的本质是将错误检测代码和错误处理代码分离。
(ps:编程时,隐去对异常处理的具体代码,只抛出异常给调用者,使程序更简洁。) - 异常处理的基本定义格式:
try{
//可能出错产生异常的代码
throw 表达式;
}
catch(type1){
//对应类型1的异常处理代码
}
catch(type2){
//对应类型2的异常处理代码
}
....//更多类型的异常处理代码
-
try关键字后的代码块中通常放入可能出现异常的代码,随后的catch块则可以是一个或多个。catch块主要用于异常对应类型的处理,catch关键字后是对应类型的参数。
try块中代码执行后一旦出现异常操作,程序便会根据抛出的异常类型去逐步遍历catch代码块(此步骤与switch控制结构相似),当遍历到对应类型的catch块时,代码会跳转到对应的catch中进行异常处理。 如果try中没有抛出异常,则catch子句会被跳过不起作用。try体中可以直接抛出异常,或者在try体中调用的函数间接抛出异常。 -
ps:
(1).catch只检查捕捉到的异常类型,并不检查它们的值.
(2).如果catch中没有指定异常信息的类型,而用删节号"…",则表示可以捕捉任何类型的异常信息,一般格式为:
catch(…){ //异常处理代码 }
这种语句块必须放在try-catch结构的最后,相当于“其它”。如果作为第一个catch语句块,则后面的catch块都不起作用。
(3).如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用terminate系统函数,让程序终止运行。 -
下面是一个异常处理实例(输入总分和科目数,计算平均分),程序能同时捕获除数为0和输入为负数的异常。
#include <iostream>
using namespace std;
//输入总分和科目数,输出平均分
//捕获除数为0和输入为负数的异常
float ave(float score,int n)
{
if(n==0)
{
throw n;
}
if(n<0||score<0)
{
throw score; //抛出异常后,不再执行后面的语句
}
float a=score/n;
cout<<"平均分:"<<a<<endl;
return a;
}
int main()
{
int n;
float score;
for(int i=0;i<3;i++)
{
cout<<"总分 科目数:";
cin>>score>>n;
try
{
ave(score,n);
}
catch(int)
{
cout<<"科目数为0,输入错误"<<endl;
}
catch(float)
{
cout<<"分数或科目数为负数,输入错误"<<endl;
}
}
return 0;
}
运行结果: