精華區beta C_and_CPP 關於我們 聯絡資訊
C++ 引入了 Exception 機制,讓使用者可以用較彈性的方式處理 異常狀況。這種「強迫回報」的作法雖然把選擇權轉移給上層模組 ,但卻帶來了另一個的問題。 這個問題就是,throw exception 的動作破壞了程式正常的流程, 例如: void f() { char *p = new char[100]; ... if (...) { throw 1; } delete [] p; } 在這個簡單的例子中,假如條件測試沒有通過,也就是說,f 拋 出異常的話(而且被上層模組處理掉了),那麼原本執行到右大 括號才離開函式 f 的行為,就發生了改變,變成執行到 throw 異常的那一行敘述就中斷了,直接返迴。換句話說,delete [] p 的動作沒有被執行到。 類似這種狀況,我們就說,函式 f 不滿足 Exception-Safety。 有人會說,那不要用 C++,用支援 GC(Garbage Collection)的 語言,例如 Java 或 C# 就沒這種問題了。 事實沒這麼簡單,再看另一個例子: void g() { ... ThreadLock(Handle); ... if (...) { throw 1; } ... ThreadUnlock(Handle); } 函式 g 是一個多緒程式常見的範例。假設發生拋出異常(且被 上層模組處理掉),那這次就不只是 new 了沒有 delete 的小 事了(雖說是小事,但也很嚴重了)。這次如果只是當機,已經 算是很好的結果了,麻煩的是,萬一程式還繼續運作下去,卻間 接造成在其他的地方,出現了奇怪而無法預測的行為,就算想要 除錯,都根本不知從何著手。 簡單的說,一旦程式中有「資源配置」的動作,例如 new 一個 物件,鎖定一個關鍵區域(或多工器等執行緒物件),或其他任 何「配置、釋放」的動作,就要特別注意 throw exception 會 改變程式正常迴路的問題。 因此,要想達成 Exception Safety(異常安全)(意思是:即 使發生了異常,程式也能安全運行下去),其實是一個非常困難 的課題。有沒有考慮「異常安全」,會從最根本的層次,影響程 式碼的實作方式,也就是說,如果在最初設計的時候,沒有考量 到異常安全,最後要再追加,幾乎是不可能的(這時,重新設計 遠比改寫容易得多)。 要克服 exception 機制破壞正常程式迴路,所帶來的麻煩,最 基本(也是最有力、最重要)的手段,不是倚賴垃圾回收器,而 是徹底貫徹 RAII 的精神。但這是另一個課題了,這裏就不討論。 基於以上的原因,在一般應用上有兩個建議: 一、除非你很了解 C++ Exception 的機制,否則最好不要亂用 (不是不能用,而是不要到處亂用)。要知道,一旦函式中的 某個部份可能拋出異常,這段程式碼的迴路複雜度,就會以倍 數(甚至是級數)地增加。不當的運用,萬一出了狀況,等於 是自找麻煩。 二、除非有極端性能的考量,否則儘可能用 C++ 標準程式庫所 提供的各種工具。因為 C++ Standard 對於 Exception Safety 都有基本的要求,通常會比自己寫的程式碼安全得多。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.120.214.120