MST

星途 面试题库

面试题:C++ RAII在复杂文件操作场景下的应用

假设你需要处理多个文件,并且在不同的异常情况下需要保证文件资源正确释放。请设计一个基于RAII的类结构,实现同时操作多个文件(例如,一个文件读取数据,另一个文件写入处理后的数据),并在出现任何异常时确保所有文件都能被正确关闭。同时分析可能存在的资源竞争问题及如何避免。
17.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

基于RAII的类结构设计

  1. 文件操作类定义
#include <iostream>
#include <fstream>
#include <stdexcept>

class FileRAII {
private:
    std::fstream file;

public:
    // 构造函数,打开文件
    FileRAII(const std::string& filename, std::ios::openmode mode) {
        file.open(filename, mode);
        if (!file.is_open()) {
            throw std::runtime_error("Failed to open file: " + filename);
        }
    }

    // 析构函数,关闭文件
    ~FileRAII() {
        if (file.is_open()) {
            file.close();
        }
    }

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

    // 获取文件流对象
    std::fstream& getFileStream() {
        return file;
    }
};
  1. 多文件操作类定义
class MultiFileHandler {
private:
    FileRAII readFile;
    FileRAII writeFile;

public:
    // 构造函数,初始化多个文件
    MultiFileHandler(const std::string& readFilename, const std::string& writeFilename)
        : readFile(readFilename, std::ios::in), writeFile(writeFilename, std::ios::out) {}

    // 处理文件的函数
    void processFiles() {
        try {
            std::string line;
            while (std::getline(readFile.getFileStream(), line)) {
                // 处理数据
                std::string processedLine = line + " processed";
                writeFile.getFileStream() << processedLine << std::endl;
            }
        } catch (const std::exception& e) {
            std::cerr << "Exception occurred: " << e.what() << std::endl;
        }
    }
};

资源竞争问题及避免方法

  1. 资源竞争问题 在多线程环境下,如果多个线程同时访问和操作这些文件,可能会出现资源竞争问题。例如,一个线程正在写入文件,另一个线程同时尝试读取或写入,可能导致数据损坏或不一致。

  2. 避免方法

    • 互斥锁(Mutex):可以在访问文件流时使用互斥锁。在MultiFileHandler类中添加std::mutex成员变量,在processFiles函数中,在访问文件流之前加锁,访问结束后解锁。
class MultiFileHandler {
private:
    FileRAII readFile;
    FileRAII writeFile;
    std::mutex fileMutex;

public:
    MultiFileHandler(const std::string& readFilename, const std::string& writeFilename)
        : readFile(readFilename, std::ios::in), writeFile(writeFilename, std::ios::out) {}

    void processFiles() {
        std::unique_lock<std::mutex> lock(fileMutex);
        try {
            std::string line;
            while (std::getline(readFile.getFileStream(), line)) {
                std::string processedLine = line + " processed";
                writeFile.getFileStream() << processedLine << std::endl;
            }
        } catch (const std::exception& e) {
            std::cerr << "Exception occurred: " << e.what() << std::endl;
        }
    }
};
- **读写锁(Read - Write Lock)**:如果读操作较多,可以使用读写锁。读操作可以并发执行,写操作需要独占锁。在C++中可以使用`std::shared_mutex`实现读写锁功能。在`processFiles`函数中,根据操作类型(读或写),使用`std::unique_lock`(写操作)或`std::shared_lock`(读操作)来锁定文件流。

通过上述基于RAII的类结构设计,可以确保在异常情况下文件资源正确释放,并且通过合理使用锁机制可以避免多线程环境下的资源竞争问题。