程序有时会遇到运行阶段的错误,比如打开一个不存在的文件,请求过多内存,接受一个不能使用值……通常程序员会避免这样的的以外,而c++提供了一种功能清大的而灵活的工具——异常。
例如下面这个示例
int main(int argc, char** argv) { int x=19; int y=-x; cout<<(2*x*y/(x+y)); return 0;}上面是输出两个数的调和平均数(两个数的倒数的平均数的倒数)
对于上面程序而言编译器可能输出一个表示无穷大的浮点数值,cout将这个值输出为Inf,inf,INF(Infinitely),也可能直接崩溃(dev c++5.11)。
解决方法 1:
#include <iostream>#include<cstdlib>//for abort()using std::cout;using std::cin;using std::endl;double harmonic(double a,double b);int main(int argc, char** argv) { int x=0; int y=0; cout<<"enter two number"; while(cin>>x>>y) { int z=harmonic(x,y); cout<<"harmonic mean of "<<x <<" and "<<y<<" is "<<z<<endl; cout<<"enter next set of number<q to quit>:"; } cout<<"Bye!/n"; return 0;}double harmonic(double a,double b){ if(a==-b){ cout<<"untenable argument to harmonic/n"; std::abort(); } return 2.0*a*b/(a+b);}abort 是位于头文件cstdlib 中,其典型实现是向标准错误流发送 abnormal PRogram termination(程序终止)然后终止程序,还返回一个随实现而异的值,告诉父进程处理失败。abort刷不刷新文件缓冲区(用于存储读写到文件中的数据的内存区域)取决于实现。也可以用exit()它会刷新缓冲文件缓冲区,但不显示消息
解决方法 2: 一种比异常终止更灵活的方法是,使用函数返回值来指出问题。例如ostream类的get(void)函数通常返回下一个输入的字符的ASCII吗。但都到文件尾部时返回特殊的EOF(一般为signed char)。对haemonic()来说这种方式不管用,因为任何数值都是有效的返回值(答案)这时候我们就可以使用指针或者引用充当返回值。并使用函数返回值来指定返回的的成功和失败
#include <iostream>#include<cfloat>//for DBL_MAXusing std::cout;using std::cin;using std::endl;bool harmonic(double ,double ,double* );int main(int argc, char** argv) { double x,y,z; cout<<"enter two number"; while(cin>>x>>y) { if(harmonic(x,y,&z)) cout<<"harmonic mean of "<<x <<" and "<<y<<" is "<<z<<endl; else cout<<"one value should not be the negative" <<"of the ohter ,try again/n"; cout<<"enter next set of number<q to quit>:"; } cout<<"Bye!/n"; return 0;}bool harmonic(double a,double b,double* ans){ if(a==-b){ *ans=DBL_MAX; return false; } else{ * ans=2.0*a*b/(a+b); return true; }}解决方法 3:
#include <iostream>#include<cfloat>//for DBL_MAXusing std::cout;using std::cin;using std::endl;double harmonic(double ,double );int main(int argc, char** argv) { double x,y,z; cout<<"enter two number"; while(cin>>x>>y) { try{ z=harmonic(x,y); }catch(const char * s){ cout<<s<<endl; cout<<"Enter a new pair of number"; continue; } cout<<"harmonic mean of "<<x <<" and "<<y<<" is "<<z<<endl; cout<<"enter next set of number<q to quit>:"; } cout<<"Bye!/n"; return 0;}double harmonic(double a,double b){ if(a==-b){ throw "bad harmonic() arguments :a =-b not allowed"; } return 2.0*a*b/(a+b);}异常的格式如下
try{ //抛出异常的语句}catch(exceptionType exceptionParameter){ //异常怎么处理写在这}就像上面的示例那样throw
在try中抛出了一个错误,错误类型是一串字符。try接受到错误,然后程序跳转到catch语句块。其中exceptionType 为我们throw
抛出的参数类型。exceptionParameter是参数的名称,我们可以在catch语句块中使用这个参数。
上面代码使用了对象作为throw 的返回类型,且使用多个catch语句块
异常规范是告诉编译器一个函数师是否可能会产生异常,格式如下
int fun1()thow(bad_thing);//可能产生异常int fun2()thow();//不会产生异常上述格式可以出现在函数声明和定义上,这是c++98引入的概念,但是c++11已经摒弃这种做法了。因为其一因为会出现函数之间的调用回家打编译器的检查难度。其次如果我们更新了代码库,而以前的代码如果不修改可能会无法使用。 所以建议不要使用上述异常规范 c++11引用了noexcept来指出函数不产生异常 int main() noexcept
告诉编译器这个函数不会出现异常
还有运算符 noexcept(OperandName ) 用来判断操作数是否会引发异常
引发异常时编译器总会创建一个临时拷贝,即使异常规范和catch中指定时引用,我们会这样呢。请款下面例子:
class problem{};……void super()(proble){…… if(oh_no) { prolem oops; throw oops; }……}……try{ super();}catch(problem & p){//……}上面的oops在函数执行完就没了,所以必须拷贝一个临时变量。 既然会创建临时变量为什么要用引用呢。毕竟引用作为返回值就是节省创建副本的开销啊。这是因为因为基类的引用可以使用派生类的方法。当有一系列的异常层次结构时。这是后基类的异常类型引用将匹配所有派生类的异常。这就需要注意一点就是catch的顺序了
class bad_1{};class bad_2:public bad_1{};class bad_3:public bad_2{};……try{}catch(bad_3){}catch(bad_2){}catch(bad_1){}上面的catch语句开顺序是呵护清理的,因为bad_1是基类如果放在第一个catch中的话,抛出的所有异常都会有bad_1语句块处理,根本没有后面的catch{}什么事。
当我们调用一个函数时,我们可能不知道这个函数会抛出什么异常。但是我们也可以捕获异常。就是使用…
try{ fun()}catch(...){ cout<<"have exception";}新闻热点
疑难解答