一、RAII 是什么

RAII 全称:Resource Acquisition Is Initialization中文:资源获取即初始化

一句话核心:

把资源的申请放在「构造函数」,资源的释放放在「析构函数」;只要对象生命周期结束,资源自动释放,不用手动写释放代码。

资源指什么:堆内存、文件句柄、互斥锁、网络 Socket、数据库连接、线程句柄、OpenGL 资源等。

二、为什么需要 RAII

传统写法痛点:

  1. 手动 new 要手动 delete,容易忘、漏写 → 内存泄漏
  2. 中途 return、异常抛出,跳过释放代码 → 资源泄露
  3. 代码分支多,每个分支都要写释放,冗余、难维护

RAII 解决:不管函数正常结束、提前 return、异常崩溃,只要对象出作用域,析构必执行,资源一定自动释放。

三、RAII 核心原理

  1. 构造函数:创建对象时,自动获取 / 申请资源
  2. 析构函数:对象销毁时,自动归还 / 释放资源
  3. 利用 C++ 对象生命周期 + 栈对象自动析构 特性
  4. 程序员只负责创建对象,不用管释放

四、最简手写 RAII 示例(内存管理)

不用 RAII(传统写法,容易泄漏)

cpp

运行

void func() {
    int* p = new int[100];

    // 中间业务逻辑
    // 如果这里 return 或抛异常,下面 delete 执行不到
    // ...

    delete[] p; // 必须手动释放,极易漏
}

用 RAII 封装(自动管理)

cpp

运行

class MemRAII {
private:
    int* ptr;
public:
    // 构造:申请资源
    explicit MemRAII(int n) {
        ptr = new int[n];
    }

    // 析构:自动释放资源
    ~MemRAII() {
        delete[] ptr;
    }

    // 禁止拷贝(独占资源)
    MemRAII(const MemRAII&) = delete;
    MemRAII& operator=(const MemRAII&) = delete;

    int* get() { return ptr; }
};

使用:

cpp

运行

void func() {
    MemRAII buf(100);  // 构造自动申请内存
    int* p = buf.get();

    // 随便写逻辑、中途return、抛异常都没事
    // 函数结束,buf 栈对象销毁,自动调用析构 delete[]
}

完全不用手动释放,绝对不泄漏。

五、经典 RAII 标准库应用(必记)

1. 智能指针(最典型)

std::unique_ptr / std::shared_ptr

  • 构造:接管堆内存
  • 析构:自动 delete
  • 不用手动 new/delete,杜绝内存泄漏

2. 锁管理 std::lock_guard /std::unique_lock

cpp

运行

std::mutex mtx;

void safe_func() {
    std::lock_guard<std::mutex> lock(mtx); // 构造自动加锁

    // 临界区代码,多线程安全
    // 无论中途return、异常,离开作用域 lock 析构自动解锁
}

不用手动 lock() / unlock(),绝不会死锁、漏解锁。

3. 文件流 std::fstream

cpp

运行

{
    std::fstream fs("test.txt"); 
    // 构造打开文件
    // 离开作用域,析构自动 close()
}

不用手动 fs.close()

4. std::string、std::vector

内部堆内存都是 RAII 管理,对象销毁自动释放内部缓冲区。

六、RAII 三大特点

  1. 自动化:申请、释放全自动,不用人工干预
  2. 异常安全:抛异常也能正常析构,资源不泄漏
  3. 作用域管控:栈对象出作用域立刻释放,生命周期可控

七、RAII 开发规范(实战必遵守)

  1. 所有资源都要用 RAII 封装,禁止裸资源裸露在外
  2. 资源类禁止随意拷贝,要么 delete 拷贝,要么实现移动语义
  3. 尽量用栈对象管理资源,少用 new 堆对象套 RAII
  4. 优先用标准库:智能指针、lock_guard、容器,不要自己重复造轮子

八、面试高频问答总结

  1. RAII 是什么?资源获取即初始化,利用构造申请资源、析构释放资源,依靠对象生命周期自动管理资源。

  2. RAII 好处?自动释放、防内存泄漏、异常安全、简化代码、不用手动释放。

  3. 哪些是 RAII 应用?智能指针、互斥锁封装、文件流、容器、网络连接封装等。

  4. 为什么不能靠手动 delete/close?分支多、异常、提前 return 会跳过释放,必然资源泄漏。

更多推荐