MST

星途 面试题库

面试题:C++类析构函数中的异常安全资源管理

考虑一个C++类,它在构造函数中初始化多个外部资源,如网络连接、数据库连接和文件句柄。假设在析构函数释放这些资源时,某个资源(如数据库连接)的关闭操作可能抛出异常。如何设计析构函数,确保在任何情况下资源都能正确释放,且不会因为异常导致资源泄漏,同时也不会让析构函数中的异常传播出去。
15.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 使用try - catch块捕获异常
    • 在析构函数中,对于可能抛出异常的资源释放操作(如关闭数据库连接),使用try - catch块进行包裹。
    • 即使捕获到异常,也继续释放其他资源,确保所有资源都被释放。
    • 以下是示例代码:
class ResourceManager {
private:
    // 假设这些是资源相关的成员变量
    NetworkConnection* networkConn;
    DatabaseConnection* dbConn;
    FileHandle* fileHandle;

public:
    ResourceManager() {
        // 初始化资源
        networkConn = new NetworkConnection();
        dbConn = new DatabaseConnection();
        fileHandle = new FileHandle();
    }

    ~ResourceManager() {
        // 释放网络连接
        if (networkConn) {
            delete networkConn;
        }
        // 释放文件句柄
        if (fileHandle) {
            delete fileHandle;
        }
        // 释放数据库连接并处理可能的异常
        if (dbConn) {
            try {
                delete dbConn;
            } catch (const std::exception& e) {
                // 记录异常日志,例如使用日志库记录异常信息
                std::cerr << "Exception during database connection close: " << e.what() << std::endl;
            }
        }
    }
};
  1. RAII(Resource Acquisition Is Initialization)原则
    • 使用智能指针来管理资源,这样可以利用智能指针的自动析构机制确保资源在对象生命周期结束时自动释放。
    • 例如,将上述资源成员变量改为std::unique_ptr
class ResourceManager {
private:
    std::unique_ptr<NetworkConnection> networkConn;
    std::unique_ptr<DatabaseConnection> dbConn;
    std::unique_ptr<FileHandle> fileHandle;

public:
    ResourceManager() {
        networkConn = std::make_unique<NetworkConnection>();
        dbConn = std::make_unique<DatabaseConnection>();
        fileHandle = std::make_unique<FileHandle>();
    }

    ~ResourceManager() {
        try {
            // 智能指针会自动调用析构函数释放资源,
            // 如果数据库连接析构函数抛出异常,这里会捕获
        } catch (const std::exception& e) {
            std::cerr << "Exception during resource destruction: " << e.what() << std::endl;
        }
    }
};
  • 这种方式更简洁,并且能更好地利用C++的资源管理机制。同时,在析构函数中捕获异常是为了防止异常从析构函数传播出去,因为析构函数中抛出异常是非常危险的,可能导致程序终止或未定义行为。

通过以上两种方式(特别是使用智能指针结合try - catch的方式),可以确保在任何情况下资源都能正确释放,且不会因为异常导致资源泄漏,同时也不会让析构函数中的异常传播出去。