MST

星途 面试题库

面试题:C++中RAII与异常安全的复杂场景处理

假设有一个复杂的C++程序,其中涉及多个类通过RAII管理不同类型资源(如文件句柄、数据库连接等),在类的成员函数调用过程中可能抛出多种类型异常。请详细阐述如何设计这些类以确保整个程序在面对异常时资源能够正确释放且数据状态保持一致,并给出核心代码结构。
46.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计原则

  1. RAII 机制的坚持:每个类负责管理自己所拥有的资源,在构造函数中获取资源,在析构函数中释放资源。这样,无论异常在何处抛出,当对象生命周期结束时,其析构函数都会被调用,从而确保资源释放。
  2. 异常安全性保证:类的成员函数应提供异常安全保证,通常分为基本保证(函数失败时,程序的状态保持在有效但未指定的状态)和强保证(如果函数抛出异常,程序状态不变)。
  3. 数据一致性维护:在成员函数执行过程中,对数据的修改应设计为原子操作或者通过事务机制来保证一致性。如果一个操作涉及多个数据修改,要么全部成功,要么全部回滚。

核心代码结构示例

#include <iostream>
#include <fstream>
#include <memory>
// 模拟数据库连接类
class DatabaseConnection {
public:
    DatabaseConnection() {
        std::cout << "DatabaseConnection: Connecting to database..." << std::endl;
        // 实际连接数据库的代码
    }
    ~DatabaseConnection() {
        std::cout << "DatabaseConnection: Disconnecting from database..." << std::endl;
        // 实际断开数据库连接的代码
    }
};

// 模拟文件操作类
class FileHandler {
public:
    FileHandler(const std::string& filename) : file(filename) {
        if (!file) {
            throw std::runtime_error("FileHandler: Could not open file");
        }
        std::cout << "FileHandler: Opening file..." << std::endl;
    }
    ~FileHandler() {
        std::cout << "FileHandler: Closing file..." << std::endl;
        file.close();
    }
private:
    std::ofstream file;
};

// 主业务类,包含文件句柄和数据库连接
class MainBusinessClass {
public:
    MainBusinessClass(const std::string& filename) 
        : fileHandler(filename), dbConnection() {
        // 可以在这里进行一些初始化操作,如写入文件或数据库初始化
    }

    void performComplexOperation() {
        try {
            // 模拟一些可能抛出异常的操作
            fileHandler.file << "Writing data to file" << std::endl;
            // 假设这里进行数据库操作,可能抛出异常
            throw std::runtime_error("Simulated database operation failure");
        } catch(...) {
            // 这里可以进行一些通用的异常处理,如记录日志等
            std::cerr << "Exception caught in performComplexOperation" << std::endl;
            throw; // 重新抛出异常,让调用者处理
        }
    }
private:
    FileHandler fileHandler;
    DatabaseConnection dbConnection;
};

使用示例

int main() {
    try {
        MainBusinessClass business("test.txt");
        business.performComplexOperation();
    } catch(const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
    }
    return 0;
}

在上述代码中:

  1. DatabaseConnectionFileHandler 类分别通过RAII管理数据库连接和文件句柄资源。
  2. MainBusinessClass 类组合了 FileHandlerDatabaseConnection 对象,在其构造函数中初始化这些资源,并在 performComplexOperation 成员函数中执行可能抛出异常的操作。
  3. 通过 try - catch 块捕获并处理异常,同时在析构函数中保证资源的正确释放,从而确保整个程序在面对异常时资源能够正确释放且数据状态保持一致。