Way to C++: 6. Exception Safe

·

1 min read

前言

考慮以下函數:

int Calculate(int n) {  
    int *arr1 = new int[n];  
    int *arr2 = new int[n];  
    delete[] arr1;  
    delete[] arr2;  
    return n+1;  
}

看起來很好,在一開始 new 的陣列在離開函數時都釋放掉了。

但是其實會有問題的: 假如在 arr2 new 的時候,記憶體不夠,那該行就會拋出 Exception,直接離開 Calculate 函數,這時 arr1 請求的記憶體就沒有被釋放。

Exception Safe

Exception Safe 主要是在要求,在發生 Exception 時,整個 Process 仍然要是好的,具體來說會通常要求這兩項:

  • 沒用到記憶體要被釋放
  • 狀態要是好的
  • 在 Catch Exception 後,要可以繼續執行下去

第一項就是指 new 的要被 delete ,開過的檔案要關閉 … 等。

第二項的狀態,可以舉個例子,假如有兩個變數,一個是陣列,另一個是陣列長度,在一個好的狀態下,紀錄陣列長度的變數必須要真的記錄著正確的數值。

第三項比較像是第一項和第二項的結果。

分級

分成三種:

  • 基礎: 發生 Exception 後,狀態是好的,並且沒有 Memory Leak。
  • 強: 發生 Exception 後,狀態回歸到操作前。
  • 超級強: No Exception。

越強所需要的成本通常會越高。

例子

Copy-and-swap

在 copy assignment 通常會寫成這樣:

Foo& Foo::operator=(const Foo& foo) {  
    Foo tmp(foo); // copy initial  
    std::swap(foo..., ...); // ...  
    return &this;  
}

主要是因為通常 copy 會需要獲取新的資源,而這種操作就有可能會發生 Exception (像是記憶體不夠…)

所以把會發生 Exception 留在前面,不會發生 Exception 的時候,才開始更動物件的狀態,這樣就可以保證發生 Exception 時,物件狀態仍然是好的(當然這裡更強: 不變)。