Effective C++ 条款8 别让异常逃离析构函数

1. 当异常发生时,如果异常发生在一个try块内部,程序就会跳出该try块,并逐层寻找匹配的catch,跳出try块的过程中,会销毁该try内创建的对象并调用析构函数,如果调用析构函数的过程中又发生异常,程序就会调用标准库terminate函数(terminate函数调用abort函数)结束执行,例如:

class A{
public:
    ...
    void func(){
        ...
    }
    ~A{
       func();
       ...
    }
private:
    ...
}
View Code

由于A类的析构函数需要调用func函数,而func函数极有可能抛出异常,这时就需要避免异常逃离析构函数.

2. 方法一:在析构函数内设置try块,一旦发生异常,立即终止程序,例如:

class A{
public:
    ...
    void func(){
        ...
    }
    ~A{
        try{
            func();
        }
        catch(...){
            std::abort();
            制作运转记录,记下对func调用失败
        }
    }
private:
    ...
}
View Code

这样可以在func函数发生异常时避免异常从析构函数内释放出去.

    方法二:吞下func发生的异常,例如:

class A{
public:
    ...
    void func(){
        ...
    }
    ~A{
        try{
            func();
        }
        catch(...){
            制作运转记录,记下对func调用失败
        }
    }
private:
    ...
}
View Code

    方法三:前两者都无法对"导致func抛出异常"做出什么反应,另一个方法是避免func()在析构函数内执行,由客户来调用func函数,为避免客户忘记执行,需设立flag标记客户是否调用,如果客户没有调用,在析构函数内调用该函数:

class A{
public:
    ...
    void func(){
       flagg=true;
        ...
    }
    ~A{
        if(!flagg){
            try{
                tmp.func();
            }
            catch(...){
                std::abort();
                制作运转记录,记下对func调用失败
            }
        }
    }
private:
    ...
    bool flagg;
}
View Code

这样把调用func的责任从A类的析构函数转移到客户,从而给客户一个“提前处理异常”的机会.

3. 总结:

    1). 析构函数绝对不要吐出异常.如果一个被析构函数调用的函数可能吐出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或终止程序.

    2). 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作.

    

原文地址:https://www.cnblogs.com/reasno/p/4749763.html