C 異常安全

2021-07-02 05:10:55 字數 2370 閱讀 8404

**:

異常安全的**是指,滿足兩個條件

1異常中立性 :

是指當你的**(包括你呼叫的**)引發異常時,這個異常 能保持原樣傳遞到外層呼叫**

2.異常安全性:

一段**要具有異常安全性,必須同時具有異常中立性和一定等級的異常安全性保證

異常安全的等級一般有:

1,函式提供基本保證(the basic guarantee)(不會發生記憶體洩漏並且程式內的每個物件都處在合法的狀態,沒有流錯位,沒有野指標,但是不是每個物件的精確狀態是可以預期的,如可能發生異常後,指標處在空指標狀態,或者某種預設狀態,但是客戶無法預知到底是哪乙個),對於達成基本保證可以多使用智慧型指標來管理資源

2,函式提供強力保證(the strong guarantee),強力保證含義是,成功或者回滾保證,發生異常的函式對程式來說,沒有任何改動,提供發生異常時候的回滾機制。

呼叫提供強力保證的函式之後,僅有兩種可能的程式狀態:像預期一樣成功執行了函式,或者函式回滾繼續保持函式被呼叫時當時的狀態。與之相比,如果呼叫只提供基本保證的函式引發了異常,程式可能存在於任何合法的狀態。

函式提供強力保證的有效解決辦法是

copy-and-swap:

先做出乙個你要改變的物件的copy,然後在這個copy上做出全部所需的改變。如果改變過程中的某些操作丟擲了異常,最初的物件保持不變。在所有的改變完全成功之後,將被改變的物件和最初的物件在乙個不會丟擲異常的操作中進行swap。

3. 函式有不丟擲保證(the nothrow guarantee),對於所有對內建型別(例如,ints,指標,等等)的操作都是不丟擲(nothrow)的(也就是說,提供不丟擲保證)。這是異常安全**中必不可少的基礎構件。

注意事項:

異常安全 最關鍵的是:swap ctor dctor 不發生異常保證,只有成功或者終止程式兩種狀態

乙個函式的異常安全等級,是取決於它所呼叫的函式中最低異常安全等級的函式。

c++11新增了noexcept關鍵字,在void func() noexcept{}noexcept保證了這個函式不會丟擲異常,只有終止程式和成功執行兩種狀態。

noexcept可以接受乙個常量表示式,noexcept(constexpr。。。)當常量表示式為轉換為true說明該函式保證不丟擲異常。

從異常安全的觀點看,不丟擲的函式(nothrow functions)是極好的,但是在 c++ 的 c 部分之外部不呼叫可能丟擲異常的函式簡直就是寸步難行。使用動態分配記憶體的任何東西(例如,所有的 stl 容器)如果不能找到足夠的記憶體來滿足乙個請求,在典型情況下,它就會丟擲乙個 bad_alloc 異常。只要你能做到就提供不丟擲保證,但是對於大多數函式,選擇是在基本的保證和強力的保證之間的。

但是,不是所有函式都能做出異常保證的,考慮這樣乙個函式,函式內部的函式內是乙個對資料庫的操作,一旦異常發生,難以撤銷對資料庫的更改。如果想對這樣的函式做到異常的strong guarantee保證,就是非常困難度事情。

所以對於只對區域性變數改變的函式保證異常安起會相對比較容易。如果函式的操作中牽扯到全域性變數等等,就變得困難的多。

解決異常安全的好辦法:

1,多使用raii,使用智慧型指標來管理記憶體。由於unwind機制的保證,當異常發生時,函式棧內已構造的區域性物件的析構函式會被一一呼叫,在析構函式內釋放資源,也就杜絕了記憶體洩漏的問題。

2,做好程式設計。特別是異常發生時的回滾機制的正確使用,copy-and-swap是有效的方法。

3,注意需要異常保證的函式內部的呼叫函式,異常安全等級是以有最低等級異常保證的函式確定的。

乙個系統即使只有乙個函式不是異常安全的,那麼系統作為乙個整體就不是異常安全的,因為呼叫那個函式可能發生洩漏資源和惡化資料結構。

4,對於一些需要保證效能的程式,在提供基本的異常安全時,要注意,棧解退機制只是呼叫析構函式,對於內建型別的操作不會被回滾,所以。像起累加器作用的一些內建型別變數,應該注意在函式成功執行後再進行累加。避免資料結構惡化。重新分配資源給原本已經持有資源的變數,應該先清空釋放變數的資源,指標再設定為nullptr,防止資源重新分配過程中丟擲異常,導致指標變為野指標的問題。

5,流物件,資源物件,new物件,不應該直接作為引數,一旦丟擲異常,就可能會導致嚴重的問題,函式也許會被錯誤的執行,資源也許會洩漏。對於函式引數和函式內使用的全域性變數,應該保證在進入函式內部是是正常狀態。

6.減少全域性變數的使用,對包含全域性變數的函式做異常安全是比較困難的事情,棧解退也只對區域性變數起效果。

7,如果不知道如何處理異常,就不要捕獲異常,直接終止比吞掉異常不處理要好

8.保證 構造 析構 swap不會失敗

這裡有個注意事項:

在建構函式中,如果丟擲異常,是不會呼叫當前正在構造的類的析構函式的,因為當前正在構造的類沒有構造完成,只會析構已經構造完成成員和父類,so,極易導致記憶體洩漏,這裡要謹慎處理,使用raii,智慧型指標,noexcept保證不會丟擲異常和惡化資料。

C 異常安全的思考

異常安全的 是指,滿足兩個條件 1異常中立性 是指當你的 包括你呼叫的 引發異常時,這個異常 能保持原樣傳遞到外層呼叫 2.異常安全性 1,丟擲異常後,資源不洩露,2,丟擲異常後,不會使原有資料惡化 例如正常指標變野指標 3。少些try catch,因為大量的try catch會影響 邏輯。導致 醜...

異常安全的C 類

題目 類cmystring的宣告如下 class cmystring 請實現複製運算子過載函式,要求異常安全 即當用乙個物件賦值發生異常時已有物件不發生改變 cmystring cmystring operator const cmystring str return this 這段 實現了異常安全...

C 基礎之異常安全

目錄 異常 throw表示式 try catch語句塊 例 異常處理 異常是程式在執行期間產生的問題。c 異常是指在程式執行時發生的特殊情況,比如嘗試除以零的操作。異常提供了一種轉移程式控制權的方式。c 異常處理涉及到三個關鍵字 try catch throw。丟擲異常即檢測是否產生異常,在c 中,...