條款 08:別讓異常逃離析構函數

條款 08:別讓異常逃離析構函數

Prevent exceptions from leaving destructors.

如果析構函數吐出異常,可能導致不明確行爲,如下面 vector 銷燬時會調用所有元素的析構函數,這會導致不明確行爲

class A {
    ...
    ~A() {...} // 假設析構函數會吐出異常
};

void f() {
    std::vector<A> v;
    ...
}

關閉資源時經常會遇到類似問題,如處理數據庫連接時爲了方便做封裝,就可能導致析構吐出異常

class DBConnection {
public:
    static DBConnection create();
    void close();
}

class DBManager {
public:
    ...
    ~DBManager() {
        db.close();    // 可能有異常逃離析構
    }
private:
    DBConnection db;
}

{
    DBManager db(DBConnection::create());
}

方法一:明確終止或吞掉異常

~DBManager() {
    try { db.close(); }
    catch (...) {
        log();
        std::abort(); // 明確終止
    }
}

~DBManager() {
    try { db.close(); }
    catch (...) {
        log(); // 直接吞掉異常
    }
}

方法二:將析構函數中可能吐出異常的操作提取到普通函數,給用戶自行處理異常的機會

class DBManager {
public:
    ...
    ~DBManager() {
        if (!closed) {
            try {
                db.close();
            }
            catch (...) {
                log();
            }
        }
    }

    void close()    // 由客戶顯式調用,自行處理異常
    {
        db.close();
        closed = true;
    }
private:
    DBConnection db;
    bool closed;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章