条款08:别让异常逃离析构函数

Prevent exceptions from leaving destructors.

当 vector v 被销毁,编译器会负责销毁数组中的每个元素。假设数组长度为10,当第一个元素被调用析构函数时出现异常,这会导致后面9个元素没有被销毁。

有两种方式可以解决这种问题:

第一种是捕获异常的话直接结束程序:

DBConn::~DBConn() {
    try {
        db.close();    // 释放资源;
    } catch (...) {
        ...            // 标记失败;
        std::abort();  // 退出程序;
    }
}

第二种是吞下异常:

DBConn::~DBConn() {
    try {
        db.close();    // 释放资源;
    } catch (...) {
        ...            // 标记失败,并吞下异常;
    }
}

上述两种方式虽然可以解决析构函数中出现异常的问题,但是一个较佳的方式是重新设计接口,使得客户有机会对异常做出反应。例如将 close 的责任从 DBConn 析构函数转交到客户上:

void DBConn::close() {
    db.close();            // 释放资源;
    closed = true;
}

DBConn::~DBConn() {
    if (!closed) {         // 如果客户端未调用 close 函数,由析构函数负责释放资源;
        try {
            db.close();
        } catch (...) {
            ...            // 标记失败,并吞下异常;
        }
    }
}

Last updated

Was this helpful?