条款8: 不要让异常逃离析构函数

举个例子:

class DBConnection
{
    public:
        ...
        static DBConnection create();
         
        void close();
};//这个class负责数据库连接。
//为了防止用户忘了close这个数据库连接,很容易想起来定义一个辅助类:
class DBCon{
    public:
        ..
        ~DBCon(){dbc.close();}
    private:
    DBConnection dbc;
}
close如果调用成功的情况下,是没问题的。但是如果调用导致异常的话,DBConn的析构函数会传播这个异常,导致不可预料的后果。

在析构函数中产生的异常通常按照两种方式来解决:

异常产生就结束:(这样可以防止不明确的行为带来的伤害)

DBConn::~DBConn()
{
    try{
    dbc.close();
  }
catch(...){ std:abort(); } }

或者是吞下这个异常:

DBConn::~DBConn()
{
try{ dbc.close(); }catch(...){ //制作运转记录,表明调用的失败 } }

更好一点的解决方法是给DBConn自己也定义一个close函数,再用户不自己close的情况下在使用上面的做法,这样就给了用户一个处理异常的机会了:

class DBConn{
    public:
        ...
        void close()
        {
            db.close();
            close = true;
        }
        ~DBConn()
        {
            if(close == false){
                try{
            dbc.close();
         }
catch(...){ std::abort(); } } } private: bool close; DBConnection dbc; };
小结:析构函数绝对不应该吐出异常,如果一个被析构函数调用的函数可能会抛出异常,析构函数应该捕捉他们然后再吞下他们,像前面的程序做的那样。
还有如果客户应该对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通的函数做这个操作,像上面的close那样。最后的析构函数中再做进一步的亡羊补牢
posted @ 2015-10-04 21:13  eversliver  阅读(265)  评论(0编辑  收藏  举报