以下代碼運行環境為64位系統下的VS2013
C++中的異常情況:
語法錯誤(編譯錯誤):比如變數未定義、括弧不匹配、關鍵字拼字錯誤等等編譯器在編譯時間能發現的錯誤,這類錯誤可以及時被編譯器發現,而且可以及時知道出錯的位置及原因,方便改正。
執行階段錯誤:比如數組下標越界、系統記憶體不足等等。這類錯誤不易被程式員發現,它能通過編譯且能進入運行,但運行時會出錯,導致程式崩潰。
為了有效處理常式執行階段錯誤,C++中引入異常處理機制來解決此問題。
C++異常處理機制:
異常處理基本思想:執行一個函數的過程中發現異常,可以不用在本函數內立即進行處理, 而是拋出該異常,讓函數的調用者直接或間接處理這個問題。
C++異常處理機制由3個模組組成:try(檢查)、throw(拋出)、catch(捕獲)
拋出異常的語句格式為:throw 運算式;如果try塊中程式段發現了異常則拋出異常。
try
{
可能拋出異常的語句;(檢查)
}
catch(類型名[形參名])//捕獲特定類型的異常
{
//處理1;
}
catch(類型名[形參名])//捕獲特定類型的異常
{
//處理2;
}
catch(…)//捕獲所有類型的異常
{
}
棧展開:
有四個函數f1(),f2(),f3(),f4(),在f2()中調f1(),f3調()f2(),f4()調f3(),main()調f4(),並在f1()拋出一個異常,在main()用catch語句捕獲。棧展開過程如下:
參考代碼:
void f1(int i){ if (i<0) throw 1;}void f2(){ f1(-45);}void f3(){ f2();}void f4(){ f3();}int main(){ try{ f4(); } catch (int i) { cout <<"error code:"<< i <<"\n"<< endl; } system("pause"); return 0;}
運行結果:
異常捕獲的匹配規則:
try 塊裡面拋出那種類型的異常,則catch裡面捕獲哪種類型的異常,一般情況下,類型必須完全符合,但以下3種情況可以進行類型轉換:
1、允許從非const對象到const的轉換。
即throw1個非const對象,catch1個const對象
2、允許從衍生類別類型到基類類型的轉換。
即throw1個衍生類別對象,catch1個基類對象
3、將數群組轉換為指向數群組類型的指標,函數轉換為指向函數類型的指標。
異常的重新拋出:
參考代碼如下:
void fun(int i){ if (i < 0) throw - 1;}void fun2(){ try { fun(-23); } catch (int i) { cout << "errcode:" << i << "\n"; }}int main(){ fun2(); system("pause"); return 0;}
運行結果:
運行上述代碼,我們只能知道程式有錯,重新拋出後,我們不僅知道程式有錯還可以知道錯誤原因,這樣便於及時改正。
參考代碼如下:
void fun(int i){ if (i < 0) throw - 1;}void fun2(int i){ try { fun(i); } catch (int i) { switch (i) { case -1; throw "資料越界";//重新拋出 } }}int main(){ try { fun2(-34); } catch (const char *s) { cout << "error code:" << s<<"\n" << endl; } system("pause"); return 0;}
運行結果:
異常規範:
函式宣告之後,列出該函數可能拋出異常類型,並保證該函數不會拋出其他類型的異常。
1、參考代碼如下:
void fun1()throw(int)//表明只能拋出int型異常{ throw '1';}int main(){ fun1(); system("pause"); return 0;}
編譯時間出現警告:忽略異常
2、如果以常規範為throw(),表示不得拋出任何異常。
異常與建構函式和解構函式:
1、保證不在建構函式中拋出異常,因為建構函式的作用是構造對象並初始化,一旦拋出異常,有可能導致對象不完整或沒有完全初始化。
2、保證不在解構函式中拋出異常,因為解構函式的作用是完成資源的清理,一旦拋出異常,有可能導致資源泄漏(記憶體流失等等)。