C 異常安全的思考

2021-06-18 05:24:29 字數 2602 閱讀 2822

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

1異常中立性 :

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

2.異常安全性:

1,丟擲異常後,資源不洩露,

2,丟擲異常後,不會使原有資料惡化(例如正常指標變野指標)

3。。少些try catch,因為大量的try catch會影響**邏輯。導致**醜陋混亂不優雅

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

異常安全的等級一般有:

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保證不會丟擲異常和惡化資料。

參考文章:

1:物件生死劫-建構函式和析構函式異常

2:c++箴言:爭取異常安全的**

3:如何編寫異常安全的**

C 異常安全

異常安全的 是指,滿足兩個條件 1異常中立性 是指當你的 包括你呼叫的 引發異常時,這個異常 能保持原樣傳遞到外層呼叫 2.異常安全性 一段 要具有異常安全性,必須同時具有異常中立性和一定等級的異常安全性保證 異常安全的等級一般有 1,函式提供基本保證 the basic guarantee 不會發...

異常安全的C 類

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

安全的思考

安全與我們的日常生活及工作息息相關,安全事故會給當事人及其親屬帶來巨大的痛苦和損失,而很多安全事故都是由於缺乏安全意識或者安全意識不強造成的,因此培養具備良好的安全意識的個人對提公升整個社會安全水準就顯得非常重要。眾所周知,馬路上的事故發生的頻率非常高,在路上的安全標識也時刻提醒著來往的行人,但是人...