比如以下例子:
class widget //假設這個可能吐出乙個異常
};void dosomething() //v在這裡被自動銷毀
上面程式中,如果v開始銷毀,第乙個元素析構時可能丟擲異常,這時程式應該停止不然導致不明確的行為,但是後面的元素又要必須析構,不然會發生記憶體洩漏,就會陷入兩難境地。
定義乙個dbconnection類負責資料庫連線:
class dbconnection;
再建立乙個dbconn類用來管理dbconnection物件:
class dbconn
private:
dbconnection db;
};
於是允許客戶寫出這樣的**:
只要上述客戶的**呼叫close成功,一切都沒好。但如果該呼叫導致異常,dbconn析構函式會傳播該異常,也就是允許它離開這個析構函式。那會造成問題,因為那就是丟擲了難以駕馭的麻煩。
兩種方法可以避免這一問題。
方法一:如果close丟擲異常就結束程式。通常通過呼叫abort完成:
dbconn::~dbconn()
catch (...)
}
方法二:吞下因呼叫close而發生的異常:
dbconn::~dbconn()
catch ( ... )
}
這兩種方法沒什麼吸引力。問題在於兩者都無法對「導致close丟擲異常」的情況作出反應。
乙個較佳策略是重新設計dbconn介面,使其客戶有機會對可能出現的問題作出反應。
可設計如下:
class dbconn
~dbconn()
catch(...)}}
private:
dbconnection db;
bool closed;
};
上面程式提供了乙個close函式,因而賦予客戶乙個機會得以處理「因該操作而發生的異常」。dbconn也可以追蹤其所管理的dbconnection是否已被關閉,並在答案為否的情況下由其析構函式關閉它。這可防止遺失資料庫連線。然而如果dbconnection析構函式呼叫close函式,我們又將退回「強迫結束程式」或「吞下異常」的老路。
(1)析構函式絕對不要吐出異常。如果乙個被析構函式呼叫的函式可能丟擲異常,析構函式應該捕捉任何異常,然後吞下它們(不傳播)或結束程式。
(2)如果客戶需要對某個操作函式執行期間丟擲的異常做出反應,那麼class應該提供乙個普通函式(而非在析構函式中)執行該操作。
條款08 別讓異常逃離析構函式
總結 1.在析構函式中盡量不要有丟擲異常的事情發生,如果析構函式中丟擲了異常,析構函式應該自己捕捉這個異常,然後根據程式需要終止程式或者吞下這個異常然繼續執行程式 2.如果需要客戶對於某個操作的函式執行期間所丟擲的異常做出反應,這個時候應該將這個丟擲異常的 函式單獨寫在乙個函式中,而不是在析構函式中...
條款08 別讓異常逃離析構函式
問題 如果乙個類的析構函式必須執行乙個動作,而該動作可能會在失敗時丟擲異常,該怎麼辦?舉個例子,假設使用過乙個class負責資料庫連線 class dbconnection 乙個較佳策略是建立乙個用來管理dbconnection資源的dbconn類,dbconn類自己提供乙個close函式,因而賦予...
別讓異常逃離析構函式
c 中並不禁止析構函式吐出異常,但是並鼓勵這樣做,看下面 當vector v被銷毀時,它有責任將其中所有的widgets銷毀並且 記憶體,而在析構第乙個元素時候,析構函式會丟擲異常,但是第二個vector的時候也會丟擲異常,這對於c 來說太多了。這會導致程式不明確的行為。c 不喜歡析構函式吐出異常。...