C++ 編程規範 7 異常與錯誤處理

來源:互聯網
上載者:User

7 異常與錯誤處理

  7.1  異常

異常是C++語言的一個強大特性,在正確使用之前需要深入瞭解,以及使用異常代碼的上下文。

原則7.1 減少不必要的異常

說明:異常對編碼技能要求更高,使用中容易出錯,首先從安全性角度考慮,盡量少用或者不用異常。

相比返回錯誤,異常的優點:
 異常可以集中捕捉,錯誤偵測與演算法處理相分離,演算法邏輯更清晰;而返回錯誤在每個返回點都

    要進行檢測與錯誤處理,代碼邏輯分散。

異常的約束更強,使用者不能忽略拋出的異常,否則程式預設會被終止,而返回錯誤則可能被忽略。

異常的缺點也很明顯:

必須檢查所有調用點是否可能拋出異常,在拋出後必須正確處理狀態和資源變數等,否則可能導

    致對象狀態不正確或者資源流失等。例如:如果f()依次調用了g()和h(),h拋出被f捕獲的異常,

    g就要當心了,避免資源流失。

必須清楚可能拋出的所有異常,並在合適的地方捕捉,如果遺漏通常會導致程式被終止。

使用異常很難評估程式的控制流程,代碼很難調試。

  目標檔案變大,編譯時間延長,效能下降。

若對異常缺乏充分理解,可能會在不恰當的時候拋出異常, 或在不安全的地方從異常中恢複。

適用異常的幾個情境:

出現“不應該出現的”失敗,且不能被忽略必須處理,比如分配記憶體失敗。

上層應用決定如何處理在底層嵌套函數中  “不可能出現的”失敗。

錯誤碼難以通過函數的傳回值或參數返回,比如流。

許多第三方C++庫使用異常,必須在系統邊界與第三方C++庫結合處使用異常便於跟這些庫整合。

在測試架構中使用異常很方便。

規則7.1 構造和解構函式不能拋出異常

說明:如果構造和解構函式執行失敗則無法安全地撤銷和復原,故這些函數不能向外拋出異常。

為了降低複雜性,建議在這類函數中實現最簡單的邏輯。

規則7.2 通過傳值的方式拋出,通過引用的方式捕獲

說明:拋出異常時,如果拋出指標,誰釋放指標就成為問題。捕捉時如果是傳值,會存在拷貝,拷貝可

能不成功(比如異常是由於記憶體耗盡造成的),而且拷貝得不到衍生類別對象,因為在拷貝時,衍生類別對象

會被切片成為基類對象。

規則7.3 確保拋出的異常一定能被捕捉到

說明:異常未被捕捉到,系統的預設行為是終止程式運行,所以要確保程式產生的異常都能被捕捉。

規則7.4 確保異常發生後資源不泄漏

說明:異常發生後,當前代碼執行序列被打斷,需要查看分配的記憶體、檔案和核心控制代碼等資源是否正確

釋放,避免資源泄漏,尤其每個可能的返回點是否正確釋放資源。

樣本:如下代碼存在記憶體流失

    int PortalTransformer::transRLS
    {
       RLS_Service* service = NULL;
       NEW( service, RLS_Service );
       parser->adoptDocument();//失敗時會拋異常
        //....
       delete service;
       service =NULL;
       return 0;
   }
調用adoptDocument出現的異常沒有在函數transRLS裡面被捕獲,而是在父函數裡面捕獲了異常的派生

類。如果發生異常,則NEW( service, RLS_Service )分配的記憶體流失。

解決方案:在函數transRLS裡面捕獲adoptDocument的異常,如果發生異常,則刪除指標service 。

規則7.5 獨立編譯模組或子系統的外部介面禁止拋異常

說明:異常處理沒有普遍通用的二進位標準,所以不允許跨模組拋異常。

  7.2  錯誤處理策略

原則7.2 建立合理的錯誤處理策略

說明:這裡所說的錯誤指執行階段錯誤,並非模組內部的編程和設計錯誤。模組內部的編程和設計錯誤

應該通過斷言標記。

在設計早期確定錯誤處理策略,包括:鑒別,嚴重程度,錯誤檢查,錯誤處理,錯誤傳遞,錯誤報表

方案。

錯誤鑒別:對每個實體(函數、類、模組),記錄該實體內部和外部的不變式、前置條件、後置條件以

及它支援的錯誤安全性保證。

錯誤嚴重程度:對於每個錯誤,標明嚴重層級。

錯誤檢查:對於每個錯誤,記載哪些代碼負責檢查它。

錯誤處理:對於每個錯誤,標明負責處理它的代碼。

錯誤報表:對於每個錯誤,標明合適的報告方法。

錯誤傳遞:對每個模組,標明使用什麼編程機制傳遞錯誤,如C++異常、CORBA異常、傳回值。

錯誤處理策略應該只在模組邊界改變。如果模組內外所使用的策略不同,則所有模組入口函數都要直

接負責由內到外的策略轉換。例如,在一個內部使用C++異常,但提供C語言的API邊界的模組中,所有

C語言的API必須用catch(„)捕獲所有異常並將其轉換為錯誤碼。

原則7.3 離錯誤最近的地方處理錯誤或轉換錯誤

說明:當函數檢查到一個自己無法解決的錯誤,而且會使函數無法繼續執行的時候,就應該報告錯誤。

如果缺乏處理的上下文,應該向上傳播錯誤。

規則7.6 錯誤發生時,至少確保符合基本保證;對於交易處理,至少符合強保證;對於原子操作,符

合無錯誤保證

說明:基本保證是指訪問對象時的狀態都是正確的;強保證是對基本保證的增強,不僅要狀態正確,

而且當失敗時狀態要復原到操作前的狀態,要麼成功要麼什麼都不做;無錯誤保證是不能出現失敗。

編碼中嚴格遵循此原則,會極大提升程式的健壯性。

符合基本保證的程式碼範例:如下代碼是解析輸入資料流到對象,流拋出異常方式呈報錯誤

    void CMessage::Parse(IStream* input)
    {
       try
       {
          m_uiMessageLen = input.ReadInteger();//失敗會拋出異常
         if (0 == m_uiMessageLen || m_uiMessageLen>MAX_MESSAGE_LEN)
           {
              throw invalid_argument("Invalid message len in CMessage::Parse ");
           }
          m_pMessage = new char[m_uiMessageLen];//失敗拋出異常
           input.Read(m_pMessage, m_uiMessageLen);//失敗拋出異常
           //.....
        }
       catch (const exception &exp){
           ResetContent();//把對象的所有欄位都設定為無效
           throw exp;
        }
       return;
    }
上例確保對象欄位的值要麼都有效要麼都無效,不會出現部分有效部分無效的情況,否則必須處理異

常被拋出時的對象狀態,給調用者帶來麻煩,容易遺漏。故介面應該至少符合基本保證。

可以把該函數改造為符合強保證,如下:

    void CMessage::Parse(IStream* input)
    {
       CMessage temp;
       try
        {
           temp .m_uiMessageLen = input.ReadInteger();//失敗會拋出異常
           if (0 == temp .m_uiMessageLen || temp .m_uiMessageLen>MAX_MESSAGE_LEN)

           {
              throw invalid_argument("Invalid messageLen in CMessage::Parse ");
           }
           temp .m_pMessage = new char[temp .m_uiMessageLen];//失敗拋出異常
           input.Read(temp .m_pMessage, temp .m_uiMessageLen);//失敗拋出異常
           //.....
        }
       catch (const exception &exp){
           temp .ResetContent();//把對象的所有欄位都設定為無效
           throw exp;
        }
       swap(temp);//成功後執行swap
       return;
    }
失敗後,對象的狀態不受影響;而成功後,執行的swap必須符合無錯誤保證,否則此函數是無法支援

強保證的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.