【本文鏈接】
http://www.cnblogs.com/hellogiser/p/constructor-destructor-exceptions.html
【問題】
構造函數可以拋出異常么?析構函數可以嗎?
【分析】
從語法上來說,構造函數和析構函數都可以拋出異常。但從邏輯上和風險控制上,構造函數可以,析構函數不推薦拋出異常。
(1)構造函數可以拋出異常
無論何時,從構造函數中拋出異常都是可以的。動態創建對象要進行兩個操作:分配內存和調用構造函數。若在分配內存時出錯,會拋出bad_alloc異常;若在調用構造函數初始化時出錯,會不會存在內存泄漏呢?答案是不會。
new運算符保證不會出現內存泄漏:
1
|
T *p =
new
T;
|
將被編譯器轉換給類似下面的樣子:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
void
allocate_and_construct() { // 第一步,分配原始內存,若失敗則拋出bad_alloc異常 try { // 第二步,調用構造函數構造對象 new (p)T; // placement new: 只調用T的構造函數 } catch (...) { delete p; // 釋放第一步分配的內存 throw ; // 重拋異常,通知應用程序 } } |
(2)析構函數不推薦拋出異常,如果析構函數可能拋出異常,那么必須要求在析構函數內消化所有異常或者結束程序。
more effective c++提出兩點理由(析構函數不能拋出異常的理由)
1)如果析構函數拋出異常,則異常點之后的程序不會執行,如果析構函數在異常點之后執行了某些必要的動作比如釋放某些資源,則這些動作不會執行,會造成諸如資源泄漏的問題。 [正常情況下調用析構函數拋出異常導致資源泄露]
2)通常異常發生時,c++的機制會調用已經構造對象的析構函數來釋放資源,此時若析構函數本身也拋出異常,則前一個異常尚未處理,又有新的異常,會造成程序崩潰的問題。 [在發生異常的情況下調用析構函數拋出異常,會導致程序崩潰]
解決方案:
1) 如果某個操作可能會拋出異常,class應提供一個普通函數(而非析構函數),來執行該操作。目的是給客戶一個處理錯誤的機會。
2) 如果析構函數中異常非拋不可,那就用try catch來將異常吞下,必須要把這種可能發生的異常完全封裝在析構函數內部,決不能讓它拋出函數之外。
【參考】
http://blog.csdn.net/liuxialong/article/details/6586083
http://www.cnblogs.com/fly1988happy/archive/2012/04/11/2442765.html