什么是 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;
}
网硕互联帮助中心




评论前必须登录!
注册