C++異常處理機制(throw、try、catch、finally)


一、什么是異常處理

  一句話:異常處理就是處理程序中的錯誤。

 

程序運行時常會碰到一些異常情況,例如:

1、做除法的時候除數為 0;

2、用戶輸入年齡時輸入了一個負數;

3、用 new 運算符動態分配空間時,空間不夠導致無法分配;

4、訪問數組元素時,下標越界;打開文件讀取時,文件不存在。


這些異常情況,如果不能發現並加以處理,很可能會導致程序崩潰。

 

 

二、異常處理機制

1、當發生異常,程序無法沿着正常的順序執行下去的時候,立即結束程序可能並不妥當。我們需要給程序提供另外一條可以安全退出的路徑,

在結束前做一些必要的工作,如將內存中的數據寫入文件、關閉打開的文件、釋放動態分配的內存空間等。

 

2、當發生異常的時候,程序馬上處理可能並不妥當(一個異常有多種處理方法,或者自己無法處理異常),需要將這個異常拋出給他的上級(直接調用者),

由上級決定如何處理。或者是自己不處理再轉交給它的上級去處理,一直可以轉交到最外層的main()函數

 

3、另外,異常的分散處理不利於代碼的維護,尤其是對於在不同地方發生的同一種異常,都要編寫相同的處理代碼也是一種不必要的重復和冗余。

如果能在發生各種異常時讓程序都執行到同一個地方,這個地方能夠對異常進行集中處理,則程序就會更容易編寫、維護。

 

在引入異常處理機制之前,異常的處理方式有兩種方法

  1、使用整型的返回值標識錯誤;

  2、使用errno宏(可以簡單的理解為一個全局整型變量)去記錄錯誤。當然C++中仍然是可以用這兩種方法的。

 

        這兩種方法最大的缺陷就是會出現不一致問題。例如有些函數返回1表示成功,返回0表示出錯;而有些函數返回0表示成功,返回非0表示出錯。

        還有一個缺點就是函數的返回值只有一個,你通過函數的返回值表示錯誤代碼,那么函數就不能返回其他的值。

 

 

鑒於上述原因,C++引入了異常處理機制

 

異常處理流程

C++ 異常處理涉及到三個關鍵字:try、catch、throw

1、throw: 當問題出現時,程序會拋出一個異常。這是通過使用 throw 關鍵字來完成的。

2、try: try 塊中的代碼標識將被激活的特定異常。它后面通常跟着一個或多個 catch 塊。

3、catch: 在您想要處理問題的地方,通過異常處理程序捕獲異常。catch 關鍵字用於捕獲異常。

4、finally:關鍵字finally放在catch之后,如果異常沒有被catch捕獲,會使用關鍵字去清理釋放資源

 

  如果有一個塊拋出一個異常,捕獲異常的方法會使用 trycatch 關鍵字。try 塊中放置可能拋出異常的代碼(判斷異常的類型),try 塊中的代碼被稱為保護代碼。

  catch后面對應每個異常的處理方法。

  以除法除0舉例。代碼如下所示:

  

#include <iostream>
using namespace std;

double division(int a, int b)
{
    if (b == 0)
    {
        throw "Division by zero condition!";
    }
    return (a / b);
}

int main()
{
    int x = 50;
    int y = 0;
    double z = 0;
    //try\catch的使用和switch\case的使用類似
    try {
        z = division(x, y);
        cout << z << endl;
    }
    catch (const char* msg) {
        cerr << msg << endl;
    }
   //finally{}
    return 0;
}

 

三、幾個概念

 

1、棧展開

棧展開指的是:當異常拋出后,匹配catch的過程。

       拋出異常時,將暫停當前函數的執行,開始查找匹配的catch子句。沿着函數的嵌套調用鏈向上查找,直到找到一個匹配的catch子句,或者找不到匹配的catch子句。

棧展開的時候,會通過析構函數或者是delete銷毀局部對象(從開始匹配位置到確認匹配這一段中間位置的資源會被釋放)

 

 

2、析構函數應該從不拋出異常。

如果析構函數中出現異常,那么就應該在析構函數內部將這個異常進行處理,而不是將異常拋出去。

為什么不應該?拋出異常的就是棧展開的過程,而棧展開會調用析構函數銷毀局部對象,這樣多次調用析構函數會導致程序崩潰(內存泄漏)

 

3、構造函數可以拋出異常

  當構造函數內出現異常,可以選擇將異常拋出,在棧展開的過程調用析構函數釋放已申請的內存,也可以在內部將異常處理,手動調用delete釋放

 

4、catch捕獲所有異常

語法:在catch語句中,使用三個點(…)。即寫成:catch (…)   這里三個點是“通配符”,類似 可變長形式參數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM