欢迎光临
我们一直在努力

深入理解C++ RAII

什么是 RAII

RAII 是 Resource Acquisition Is Initialization 的缩写,中文常译为“资源获取即初始化”。它是 C++ 中管理资源、保证异常安全的核心惯用法。

它的核心思想是:

把资源的生命周期绑定到一个栈对象的生命周期上。

具体做法:

  • 在构造函数中获取资源(如内存、文件、锁、套接字、句柄等)。

  • 在析构函数中释放资源。

  • 使用一个栈对象来持有这个资源。

  • 当栈对象离开作用域时,C++ 会自动调用它的析构函数,从而自动释放资源。

  • 即使发生异常,栈展开(stack unwinding)也会保证已构造的栈对象被析构。

因此,RAII 不仅能防止内存泄漏,也能防止文件未关闭、锁未释放、句柄泄漏等问题。


RAII 的关键点

  • 资源在构造函数中获取

    • 如果获取失败,可以抛出异常,表示对象构造失败。

  • 资源在析构函数中释放

    • 析构函数不应抛出异常,否则可能导致程序终止。

  • 对象通常放在栈上,或由智能指针管理

    • 栈对象离开作用域自动析构。

    • 堆对象可以用 std::unique_ptr、std::shared_ptr 等管理。

  • 利用 C++ 的确定性析构

    • 与垃圾回收不同,C++ 能确定资源何时释放。

    • 适合管理非内存资源,如文件、互斥锁、网络连接。

  • 正确处理拷贝和移动

    • 如果资源不可共享,应禁止拷贝,或实现移动语义转移所有权。

    • 否则可能重复释放同一资源。

  • 标准库中大量使用 RAII

    • std::string、std::vector 管理内存。

    • std::unique_ptr、std::shared_ptr 管理动态对象。

    • std::lock_guard、std::unique_lock 管理互斥锁。

    • std::fstream、std::ofstream 管理文件。

    • std::jthread(C++20)管理线程。

  • #include <iostream>
    #include <stdexcept>
    #include <cstddef>

    class IntArray {
    public:
    // 构造函数:获取资源(动态内存)
    explicit IntArray(std::size_t n)
    : size_(n), data_(new int[n]) {
    std::cout << "IntArray: 分配了 " << n << " 个 int\\n";
    for (std::size_t i = 0; i < n; ++i) {
    data_[i] = 0;
    }
    }

    // 析构函数:释放资源
    ~IntArray() {
    delete[] data_;
    std::cout << "IntArray: 释放了内存\\n";
    }

    // 禁止拷贝,防止两个对象管理同一块内存导致 double free
    IntArray(const IntArray&) = delete;
    IntArray& operator=(const IntArray&) = delete;

    // 简单访问接口
    int& operator[](std::size_t i) {
    return data_[i];
    }

    std::size_t size() const {
    return size_;
    }

    private:
    int* data_;
    std::size_t size_;
    };

    void doSomething() {
    // arr 是栈对象,构造时获取资源
    IntArray arr(5);

    arr[0] = 10;
    arr[1] = 20;

    std::cout << "arr[0] = " << arr[0]
    << ", arr[1] = " << arr[1] << "\\n";

    // 模拟异常:即使这里抛出异常,arr 的析构函数也会被调用
    throw std::runtime_error("发生异常");

    // 下面这行不会执行
    std::cout << "这行不会执行\\n";
    }

    int main() {
    try {
    doSomething();
    } catch (const std::exception& e) {
    std::cout << "捕获异常: " << e.what() << "\\n";
    }

    std::cout << "程序继续执行\\n";
    return 0;
    }

    赞(0)
    未经允许不得转载:171主机测评 » 深入理解C++ RAII
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址