Way to C++: 6. Exception Safe
前言
考慮以下函數:
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 時,物件狀態仍然是好的(當然這裡更強: 不變)。