prevent exception from leving destructors.
c++並不禁止析構函式吐出異常,但它不鼓勵這樣做.這是有原因的,考慮以下**:
class widget // 假設這個可能吐出乙個異常
};void dosomething() // v在這裡被自動銷毀
當vector v被銷毀,它有責任銷毀其內含的所有widgets.假設v內含十個widgets,而在析構第乙個元素期間,有個異常被丟擲.其他九個widgets還是應該被銷毀(否則它們儲存的任何資源都會發生洩漏),因此v應該呼叫它們各個析構函式.但假設在那些呼叫期間,第二個widgets析構函式右丟擲異常.現在有兩個同時作用的異常,這對c++而言太多了.在兩個異常同時存在的情況下,程式若不是結束執行就是導致不明確行為.本例中它會導致不明確的行為.使用標準程式庫的任何其他容器或tr1的任何容器或甚至array,也會出現相同情況.容器或array並非遇上麻煩的必要條件,只要析構函式吐出異常,即使並非使用容器或arrays,程式也可能過早結束或出現不明確行為.c++不喜歡析構函式吐出異常.
這很容易理解,但如果析構函式必須執行乙個動作,而該動作可能會在失敗時丟擲異常,該怎麼辦?例如,假設使用乙個 class 負責資料庫連線:
class dbconnection ;
為確保客戶不忘記在dbconnection物件上呼叫close(),乙個合理的想法是建立乙個用來管理dbconnection資源的 class,並在其析構函式中呼叫close.
class dbconn
private:
dbconnection db;
};
這便允許客戶寫出這樣的**:
// 在區塊結束點,dbconn物件被銷毀,自動呼叫close
只要呼叫close成功,一切都很美好.但如果該呼叫導致異常,dbconn析構函式會傳播該異常,也就是允許它離開這個析構函式.那會造成問題,因為那就是丟擲了難以駕馭的麻煩.
兩個辦法可以避免這一問題,dbconn的析構函式可以:
1.如果close丟擲異常就程式結束.通常通過呼叫abort完成:
dbconn::~dbconn()
catch ( ... )
}
如果程式遭遇乙個"於析構期間發生的錯誤"後無法繼續執行,"強迫結束程式"是個合理選項.畢竟它可以阻止異常從析構函式傳播出去(那會導致不明確行為).也就是說呼叫abort可以搶先制"不明確行為"於死地.
2.吞下因呼叫close而發生的異常:
dbconn::~dbconn()
catch ( ... )
}
一般而言,將異常吞掉是個壞主意.然而有時候吞下異常也比負擔"草率結束程式"或"不明確行為帶來的風險"好.
這些辦法都沒有吸引力,問題在於兩者都無法對"導致close丟擲異常"的情況作出反應.
乙個較佳的策略是重新設計dbconn介面,使其客戶有機會對可能出現的問題作出反應.例如dbconn自己可以提供乙個close函式,因而賦予客戶乙個幾乎得以處理"因該操作而發生的異常".dbconn也可以追蹤其所管理的dbconnection是否已被關閉,如果否則由其析構函式關閉.這可防止遺失資料庫連線.然而如果dbconnection析構函式呼叫close失敗,又將回到"強迫結束程式"或"吞下異常"的老路:
class dbconn
~dbcoon() catch ( ... ) }}
private:
dbconnection db;
bool closed;
};
把呼叫close的責任從dbconn析構函式上移到dbconn客戶上,是可以的.如果某個操作可能在失敗時丟擲異常,而又存在某種需要必須處理該異常,那麼這個異常必須來自析構函式以外的某個函式.因為析構函式吐出異常就是危險,總會帶來"過早結束程式"或"發生不明確行為"的風險.本例要說的是,由客戶自己呼叫close並不會對他們帶來負擔,而是給他們乙個處理錯誤的機會,否則他們沒機會響應.如果他們不認為這個機會有用,可以忽略它,依賴dbconn析構函式去呼叫close.
注意:
析構函式絕對不要吐出異常.如果乙個被析構函式呼叫的函式可能丟擲異常,析構函式應該捕捉任何異常,然後吞下它們(不傳播)或結束程式.
如果客戶需要對某個操作函式執行期間丟擲的異常做出反應,那麼 class 應該提供乙個普通函式(而非在析構函式中)執行該操作.
Effective C 條款52 第8章
write placement delete if you write placement new placement new 和 placement delete 並非在c 常見.回憶 條款16和 條款17,當寫乙個如下所示的 new 表示式 widget pw new widget 共有兩個函式...
Effective C 條款15 第3章
provide access to raw resources in resources managing classes 資源管理類 resource managing classes 很棒.它們是對抗資源洩露的堡壘.在乙個良好的環境中將依賴這樣的classes來處理和資源之間的所有互動.而不是直...
Effective C 條款23 第4章
prefer non member non friend functions to member functions 想象有個 class 用來表示網頁瀏覽器,這樣的 class 可能提供眾多函式,如下所示 class webbrowser 許多使用者會想一整個執行所有這些動作,因此webbrows...