***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
二、Constructors,Destructors and Assignment Operators
Rule 08:Prevent exceptions from leaving destructors
规则08:别让异常逃离析构函数
C++并不禁止析构函数吐出异常,但它不鼓励你这样做。
首先,看下面这个例子:
class Widget {
public:
...
~Widget( ) { ... } // 假设这里可能吐出异常
};
void doSomething()
{
std::vector<Widget> v;
...
} // v在这里被销毁
2.即使知道C++讨厌,但我们无法避免要面对它
如果析构函数必须执行某个动作,但这个动作可能导致异常,怎么办呢?
依旧用书上的例子,用一个类来负责数据库连接:
class DBConnection {
public:
...
static DBConnection create();
void close();
};但是为了确保客户不忘记在 DBConnection 对象上调用close(),一个合理的想法是创建一个用来管理DBConnection资源的class并在其析构函数中调用close,如同下面这种:
class DBConn {
public:
...
~DBConn()
{
db.close();
}
private:
DBConnection db;
};{
DBConn dbc( DBConnection::create() );
...
}<span style="white-space:pre"> </span>// 在块结束时DBConn对象被销毁,因为自动为DBConnection对象调用close对于这个情况有两个方案来搞定:
<1>plan01:
如果 close 抛出异常就结束程序。通常就通过调用abort完成:
DBConn::~DBConn( )
{
try{ db.close(); }
catch( ... ) {<span style="font-family: Arial, Helvetica, sans-serif;"> </span><pre name="code" class="cpp"> 制作运转记录,记下对close的调用失败;std::abort(); }}
<2>plan02:
吞下因调用close而发生的异常
DBConn::~DBConn( )
{
try { db.close(); }
catch ( ... ) {
制作运转记录,记下对close的调用失败;
}
}
3.更好的方法?
上面两种方法都是因为 无法对 导致close抛出异常 的情况作出反应。
所以,更好的办法,就是 重新设计 DBConn 的接口,比如:
class DBConn {
public:
...
void close()<span style="white-space:pre"> </span>// 供用户使用的新函数
{
db.close();
closed = true;
}
~DBConn()
{
if( !closed ) {
try {<span style="white-space:pre"> </span>// 如果用户没有关闭连接,则执行关闭连接
db.close();
}
catch ( ... ) {<span style="white-space:pre"> </span>// 如果关闭动作失败
制作运转记录,记下对close的调用失败;
....
}
}
}
private:
DBConnection db;
bool closed;
};这个方案的优点,把调用close责任给到用户手上,但是还设置了一个双保险,让程序更加安全。
4.请记住:
★ 析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(让它们不能传播出去)或者 结束程序。
★ 如果客户需要对某个操作函数运行期间抛出异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
原文地址:http://blog.csdn.net/lttree/article/details/41007475