Namespaces
Variants

RAII

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

资源获取即初始化 (Resource Acquisition Is Initialization,简称RAII)是一种C++编程技术 [1] [2] ,该技术将必须在使用前获取的资源生命周期(包括已分配的堆内存、执行线程、打开的套接字、打开的文件、锁定的互斥量、磁盘空间、数据库连接等任何有限存在的资源)与对象的 生存期 相绑定。

RAII保证资源对任何可能访问该对象的函数都可用(资源可用性是一个 类不变量 ,消除了冗余的运行时检测)。它还保证在其控制对象的生命周期结束时,所有资源都会按照获取顺序的逆序释放。同样地,如果资源获取失败(构造函数因异常退出),所有已完全构造的成员和基类子对象所获取的资源,将按照初始化顺序的逆序释放。这利用了核心语言特性( 对象生命周期 作用域退出 初始化顺序 栈回溯 )来消除资源泄漏并保证异常安全。该技术的另一个名称是 作用域绑定资源管理 (SBRM),得名于RAII对象因作用域退出而结束生命周期的基本使用场景。

RAII 可概括如下:

  • 将每个资源封装到一个类中,其中
  • 构造函数获取资源并建立所有类不变量,若无法完成则抛出异常,
  • 析构函数释放资源且绝不抛出异常;
  • 始终通过RAII类的实例来使用资源,该类要么
  • 其自身具有自动存储期或临时生存期,或
  • 其生存期受限于某个自动对象或临时对象的生存期。

移动语义使得资源与所有权在对象之间、容器内外以及跨线程时能够进行转移,同时确保资源安全。

(since C++11)

具有 open() / close() lock() / unlock() init() / copyFrom() / destroy() 成员函数的类是非RAII类的典型示例:

std::mutex m;
void bad() 
{
    m.lock();             // 获取互斥锁
    f();                  // 如果 f() 抛出异常,互斥锁将永远不会被释放
    if (!everything_ok())
        return;           // 提前返回,互斥锁永远不会被释放
    m.unlock();           // 如果 bad() 执行到该语句,互斥锁会被释放
}
void good()
{
    std::lock_guard<std::mutex> lk(m); // RAII 类:互斥锁获取即初始化
    f();                               // 如果 f() 抛出异常,互斥锁会被释放
    if (!everything_ok())
        return;                        // 提前返回,互斥锁会被释放
}                                      // 如果 good() 正常返回,互斥锁会被释放

标准库

遵循RAII机制的C++库类会自主管理资源: std::string std::vector std::jthread (C++20起) 以及其他许多类,它们通过构造函数获取资源(出错时抛出异常),通过析构函数释放资源(绝不抛出异常),且无需显式清理。

此外,标准库提供了多种RAII包装器来管理用户提供的资源:

(since C++11)

注释

RAII不适用于管理那些在使用前未被获取的资源:CPU时间、核心可用性、缓存容量、熵池容量、网络带宽、电力消耗、栈内存。对于此类资源,C++类构造函数无法保证在对象生命周期内资源的可用性,必须使用其他资源管理方法。

外部链接

  1. Stroustrup的C++常见问题解答中的RAII
  2. C++核心指南 E.6 "使用RAII防止资源泄漏"