异常
程序在运行过程中出现的错误称为异常。
异常处理
对异常的处理称为异常处理。 处理程序中的错误非常困难,如服务器上长期运行的服务程序有80%的代码用于错误检测和错误处理。
传统的异常处理
基本是采取判断或分支语句来实现
例一:#include<iostream> using namespace std; int main(void){ int m,n; cin>>m>>n;//m/n; if(n==0) cout<<"除数为零,错误"; else cout<<m/n; }
优点:
可以满足小型应用程序的需要
缺点:
在一个大型软件系统中,包含许多模块,每个模块又包含许多函数,函数之间又相互调用,比较复杂。如果在每一个函数中都设置处理异常的程序段,会使程序过于复杂和庞大。传统的异常处理机制无法保证程序的可靠运行,而且采用判断或分支语句处理异常的方法不适合大量异常的处理,更不能处理不可预知的异常。
C++提供的异常处理
C++提供的异常处理机制逻辑结构非常清晰,而且在一定程度上可以保证程序的鲁棒性(或健壮性,robustness)
抛出异常(throw)、检查异常(try块)、和捕获(catch块)
基本思想:把需要检测的程序放到try块中,把处理异常的程序放到catch中。如果在执行一个函数时发现异常,不在函数内立即处理异常,而是抛出异常信息,传递给他的上一级函数(主调函数),它的上一级函数捕获这个异常后再近些处理。如果上一级函数也不处理,就逐层向上传递。如果遇到最高一级(如main函数),就只能终止程序的执行
优点:
这样的异常处理方法使得异常的引发和处理机制分离,而不是由同一个函数完成。这样做法的好处是使底层函数(被调用函数)着重于解决实际任务,而不必过多地考虑对异常的处理,以减轻底层函数的负担,把异常处理的任务上移到上层去处理。
1、try 语句
try语句的作用是启动异常处理机制。
格式:
try
{
<语句序列>
}
例二:try{ f(filename); }
2、throw 语句
throw语句用于在发现异常情况时抛掷(产生)异常对象。
格式:
throw <表达式>;
例三:void f(char * filename){ ifstream file(filename); if(file.fail) throw filename;//产生异常对象 }
3、catch 语句
catch语句用于捕获throw 抛掷的异常对象并处理相应的异常。
格式:
catch(<类型><变量>)
{
<语句序列>
}
例四:#include<iostream> using namespace std; void fun(int x){ try{ if(x==0) throw 1; if(x==1) throw 'a'; if(x==2) throw 1.0; throw ""; } catch(int){ cout<<"x=0"; } catch(char){ cout<<"x=1"; } catch(double){ cout<<"x=2"; } catch(const char *){ cout<<"x="<<x; } } int main(void){ int x; cin>>x; fun(x); }
异常处理的详细方法:
- 首先将需要检查的、也是容易引起异常的语句或程序段放在try块的{}内
- 如果在执行try块的复合语句过程中没有发生异常,则跳过catch语句,继续执行
- 如果执行try内的复合语句或被调用函数发生异常,则throw语句抛出一个异常信息,转到它的上一级函数
- Throw抛出的异常信息传到try_catch结构,系统寻找与之匹配的catch子句。
- 执行异常处理语句后,程序继续执行catch子句后面的语句。
注意:
- 被检测的语句必须放在try块中,否则不起作用 try和catch作为一个整体出现,不能单独使用,且二者之间也不能插入其他语句
- try和catch中必须使用有花括号括起来的复合语句,即使花括号内只有一个语句也不能省略花括号
- 一个try_catch结构中只能有一个try块,但却可以有多个catch块,以便与不同的信息匹配。catch后面的括号中,一般只写异常信息的类型名,catch只检查所捕获的异常信息的类型,不检查他们的值。
- 如果在子句catch中没有指定异常信息的类型,而用了删节号“…”,则表示它可以捕获任何类型的异常信息。
例五:#include<iostream> using namespace std; void fun(int x){ try{ if(x==0) throw 1; if(x==1) throw 'a'; if(x==2) throw 1.0; throw ""; } catch(int){ cout<<"x=1"; } catch(...){ cout<<"..."<<x; } } int main(void){ int x; cin>>x; fun(x); }`
- try - catch结构可以和throw出现在同一函数中,也可以不在函数中。在某种情况下,throw语句被多次调用。此时,它将把当前正在处理的异常信息再次抛出,给其上一层catch块处理。(try的嵌套使用)
例六:#include<iostream> using namespace std; void fun(int x){ try{ if(x==1) throw 1; if(x==2) throw 'a'; throw " "; } catch(int){ cout<<"x=1"; throw 1; } catch(char){ cout<<"x=2"; throw 'a'; } catch(const char *){ cout<<"x="<<x; throw " "; } } int main(void){ int x; cin>>x; try{ fun(x); } catch(int){ cout<<" int"; } catch(char){ cout<<" char"; } catch(const char *){ cout<<" const char *"; } }
- 在C++中,一旦抛出一个异常,而程序又不捕获的话,那么系统就会调用一个系统函数terminate,由它调用abort终止程序。