名前空間
変種
操作

RAII

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 

Resource Acquisition Is Initialization、略してRAIIは、C++プログラミングにおけるテクニックです[1][2]。これは、使用前に取得しなければならないリソース(確保されたヒープメモリ、実行スレッド、開かれたソケット、開かれたファイル、ロックされたミューテックス、ディスク領域、データベース接続など、供給が限られているあらゆるもの)のライフサイクルを、オブジェクトのライフサイクルに結びつけます。

RAIIは、オブジェクトにアクセスする可能性のあるどの関数に対してもリソースが利用可能であることを保証します(リソースの利用可能性はクラス不変条件であり、冗長な実行時テストを不要にします)。また、制御するオブジェクトのライフサイクルが終了したときには、すべてのリソースが取得とは逆の順序で解放されることも保証します。同様に、リソースの取得が失敗した場合(コンストラクタが例外で終了した場合)、完全に構築されたすべてのメンバーおよび基底サブオブジェクトによって取得されたすべてのリソースは、初期化とは逆の順序で解放されます。これにより、コア言語機能(オブジェクトのライフサイクルスコープからの脱出初期化の順序スタックアンワインディング)が活用され、リソースリークが排除され、例外安全性が保証されます。このテクニックは、RAIIオブジェクトのライフサイクルがスコープからの脱出によって終了するという基本的なユースケースから、Scope-Bound Resource Management(SBRM)とも呼ばれます。

RAIIは以下のように要約できます。

  • 各リソースをクラスにカプセル化し、そこで
  • コンストラクタがリソースを取得し、すべてのクラス不変条件を確立するか、それができない場合は例外をスローします。
  • デストラクタがリソースを解放し、決して例外をスローしません。
  • 常にRAIIクラスのインスタンスを介してリソースを使用します。そのインスタンスは、
  • 自動ストレージ期間または一時的なライフサイクル自体を持つか、または
  • 自動または一時オブジェクトのライフサイクルによって制限されるライフサイクルを持ちます。

ムーブセマンティクスにより、リソースの安全性(resource safety)を確保しながら、コンテナ内外およびスレッド間でリソースと所有権を転送することができます。

(C++11以降)

open()/close()lock()/unlock()、またはinit()/copyFrom()/destroy()といったメンバー関数を持つクラスは、RAIIではない典型的な例です。

std::mutex m;
 
void bad() 
{
    m.lock();             // acquire the mutex
    f();                  // if f() throws an exception, the mutex is never released
    if (!everything_ok())
        return;           // early return, the mutex is never released
    m.unlock();           // if bad() reaches this statement, the mutex is released
}
 
void good()
{
    std::lock_guard<std::mutex> lk(m); // RAII class: mutex acquisition is initialization
    f();                               // if f() throws an exception, the mutex is released
    if (!everything_ok())
        return;                        // early return, the mutex is released
}                                      // if good() returns normally, the mutex is released

[編集] 標準ライブラリ

C++ライブラリクラスのうち、自身のリソースを管理するものはRAIIに従っています。std::stringstd::vectorstd::jthread(C++20以降)など多くのクラスは、コンストラクタでリソースを取得し(エラー時には例外をスロー)、デストラクタでリソースを解放し(決して例外をスローしない)、明示的なクリーンアップを必要としません。

さらに、標準ライブラリは、ユーザーが提供するリソースを管理するためのいくつかのRAIIラッパーを提供しています。

(C++11以降)

[編集] 注記

RAIIは、使用前に取得されないリソース(CPU時間、コアの利用可能性、キャッシュ容量、エントロピープール容量、ネットワーク帯域幅、電力消費、スタックメモリなど)の管理には適用されません。そのようなリソースの場合、C++クラスのコンストラクタはオブジェクトのライフサイクル中にリソースの利用可能性を保証できないため、他のリソース管理手段を使用する必要があります。

[編集] 外部リンク

  1. Stroustrup's C++ FAQにおけるRAII
  2. C++ Core Guidelines E.6 "リークを防ぐためにRAIIを使用する"
English 日本語 中文(简体) 中文(繁體)