程序有時會遇到運行階段的錯誤,比如打開一個不存在的文件,請求過多內存,接受一個不能使用值……通常程序員會避免這樣的的以外,而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";}新聞熱點
疑難解答