MST

星途 面试题库

面试题:C++ 异常规范与资源管理

假设有一个类 `ResourceHolder` 管理某种资源(例如文件句柄),使用RAII机制。请编写一个成员函数,该函数既要遵循异常规范,又要保证异常安全的强保证(strong exception safety guarantee),描述你的设计思路并写出完整代码。
26.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. RAII(Resource Acquisition Is Initialization)机制:在构造函数中获取资源,在析构函数中释放资源,确保资源在对象生命周期结束时能被正确释放。
  2. 异常规范:在C++ 11及之后,异常规范主要通过noexcept关键字来表示函数是否抛出异常。这里我们要保证函数可能抛出异常。
  3. 强异常安全保证:意味着如果函数抛出异常,程序状态应保持不变,即所有资源应保持获取前的状态,没有任何资源泄漏。

代码示例

#include <iostream>
#include <stdexcept>

class ResourceHolder {
private:
    // 模拟资源,这里用文件句柄的整数表示
    int fileHandle;

public:
    ResourceHolder() : fileHandle(-1) {}

    // 构造函数获取资源
    ResourceHolder(const std::string& filePath) {
        // 这里模拟打开文件获取文件句柄
        fileHandle = openFile(filePath);
        if (fileHandle == -1) {
            throw std::runtime_error("Failed to open file");
        }
    }

    // 析构函数释放资源
    ~ResourceHolder() {
        if (fileHandle != -1) {
            closeFile(fileHandle);
        }
    }

    // 禁止拷贝构造和赋值运算符
    ResourceHolder(const ResourceHolder&) = delete;
    ResourceHolder& operator=(const ResourceHolder&) = delete;

    // 实现移动构造和移动赋值
    ResourceHolder(ResourceHolder&& other) noexcept {
        fileHandle = other.fileHandle;
        other.fileHandle = -1;
    }

    ResourceHolder& operator=(ResourceHolder&& other) noexcept {
        if (this != &other) {
            if (fileHandle != -1) {
                closeFile(fileHandle);
            }
            fileHandle = other.fileHandle;
            other.fileHandle = -1;
        }
        return *this;
    }

    // 模拟打开文件的函数
    int openFile(const std::string& filePath) {
        // 实际实现应使用系统调用,这里简单返回一个模拟值
        if (filePath.empty()) {
            return -1;
        }
        return 1;
    }

    // 模拟关闭文件的函数
    void closeFile(int handle) {
        // 实际实现应使用系统调用
        std::cout << "Closing file with handle: " << handle << std::endl;
    }

    // 实现遵循异常规范且保证强异常安全保证的成员函数
    void performOperation(const std::string& newFilePath) {
        ResourceHolder temp(newFilePath); // 创建临时对象来获取新资源,如果获取失败会抛出异常
        // 交换当前对象和临时对象的资源
        std::swap(fileHandle, temp.fileHandle);
        // 临时对象析构时会释放旧资源
    }
};

int main() {
    try {
        ResourceHolder holder("original.txt");
        holder.performOperation("new.txt");
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    }
    return 0;
}

在上述代码中,performOperation 函数通过创建临时 ResourceHolder 对象获取新资源,若获取失败则抛出异常,不会影响原对象状态。若成功获取,通过 std::swap 交换资源,保证了强异常安全保证。同时,整个类遵循RAII机制管理资源。