Item 08-別讓異常逃離析構函數(Prevent exceptions from leaving destructors)
C++並不禁止析構函數吐出異常,但它不鼓勵你這樣做。這是有理由的。
Ex: class Widget{ public: ~Widget(){...} //假設這個可能吐出一個異常 }; void doSomething() { std::vector v; ... //v在這裡銷毀 }
當vector v被銷毀,它有責任銷毀其內含的所有Widgets,假設v內含有多個Widgets,期間只要有析構函數吐出異常,程序可能過早結束或出現不明確行為。
解決辦法:
Ex: class DBConn{ public: ~DBConn() { db.close(); } private: DBConnection db; }
如果close調用導致異常,DBConn析構函數會傳播異常
解決辦法:
1、如果close拋出異常就結束程序,通常通過調用abort完成
DBConn::~DBConn()
{
try{db.close;}
catch(...)
{
制作運轉記錄,記下對close的調用失敗;
std::abort();
}
}
2、吞下因調用close而發生的異常
DBConn::~DBConn()
{
try{db.close();}
catch(...)
{
制作運轉記錄,記下對close的調用失敗
}
}
較佳策略:重新設計DBConn接口,使其客戶有機會對可能出現的問題作出反應。
請記住:
析構函數絕對不要吐出異常;如果一個被析構函數調用的函數可能拋出異常,析構函數應該捕捉任何異常,然後吞下它們(不傳播)或結束程序。
如果客戶需要對某個操作函數運作期間拋出的異常做出反應,那麼class應該提供一個普通函數(而非在析構函數中)執行。