Item 08-别让异常逃离析构函数(Prevent exceptions from leaving destructors)
C++并不禁止析构函数吐出异常,但它不鼓励你这样做。这是有理由的。
Ex:
class Widget{
public:
~Widget(){...} //假设这个可能吐出一个异常
};
void doSomething()
{
std::vector<Widget> 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应该提供一个普通函数(而非在析构函数中)执行。