C++之禁止异常信息传递到析构函数外面(10)---《More Effective C++》

5 篇文章 0 订阅
3 篇文章 0 订阅

C++中禁止异常传递到析构函数外面有两个原因:1)异常转递的堆栈辗转开解的过程中,防止terminate函数被调用;2)能够帮助确保析构函数总能完成我们希望它完成的动作。

C++中有两种情况下会调用析构函数:1)正常情况下删除对象,如对象超出作用域或者对象指针被显示delete掉;
2)异常传递的堆栈辗转开解(stack-unwinding)过程中,由异常处理系统删除一个对象。
在上述两种情况下,调用析构函数时候异常可能处于激活状态也可能处于未激活状态,但是编译器却无法对其进行区分,这将使得我们的程序很脆弱。如果一个异常被激活的同时,同时析构函数也抛出了异常,这时候就会非常恐怖,程序的控制权转移到析构函数的外部,C++直接会调用terminate函数,并且会理解终止程序的运行,甚至局部对象都没有被释放。

1、一个异常被激活同时析构函数抛出异常,这将导致terminate函数立即执行:

class Session{
public:
    Session();
    ~Session();
    ...
private:
    static void logCreation(Session* objAddr);
    static void logDestruction(Session* objAddr);
};

现在我们调用logDestruction()函数:

Session::~Session(){
    logDestruction(this);
}

试想一下如果在调用logDestruction()函数的过程中抛出异常,同时该异常也将在析构函数中抛出,这感觉,是不是感觉爽歪歪哈~~~
当然有同学会说我们可以这样处理呀:调用try…catch…异常处理机制进行局部处理:

Session::~Session(){
    try{
        logDestruction(this);
    }catch(...){
        cerr<<"ERROR at address"<<this<<".\n";
    }
}

但是请注意这儿针对opertor<<运算符仍旧可能导致异常被抛出,又回到原来的老问题了。。。
所以我们的推荐解决方法如下:

Session::~Session(){
    try{
        logDestruction(this);
    }catch(...){}
}

如果异常被析构函数抛出而没有在函数内部被不捕获,析构函数就完全不会运行,将停在抛出异常的那个地方上。

Session::Session(){
    logCreation(this);
    startTransaction();
}
Session::~Session(){
    logDestruction(this);
    endTransaction();
}

如果在这里logDestruction抛出一个异常,在session构造函数内启动的transaction就没有终止。我们也许能够通过重新调整session析构函数内的函数调用顺序来消除问题,但是如果endTransaction也抛出异常的话,我们除了使用try…catch…之外别无它法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值