名前空間
変種
操作

RAII

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定(C++20未満)
noexcept 指定子(C++11)
例外
名前空間
指定子
decltype(C++11)
auto(C++11)
alignas(C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr(C++11)
ユーザ定義(C++11)
ユーティリティ
属性(C++11)
typedef 宣言
型エイリアス宣言(C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 

リソース取得は初期化である (Resource Acquisition Is Initialization) (RAII) は、使用する前に取得しなければならないリソース (確保したヒープメモリ、開いたファイル、ロックしたミューテックス、ディスク空間、データベース接続など、供給が制限されているあらゆるもの) のライフサイクルをオブジェクトの生存期間に束縛するための、 C++ のプログラミングテクニック[1][2]です。

RAII は、そのオブジェクトにアクセスできるあらゆる関数がそのリソースを利用可能であることを保証します (リソースの利用可能性はクラスの不変条件であり、冗長な実行時の判定を除去します)。 また、対応する制御オブジェクトの生存期間が終了したときにすべてのリソースが取得の逆順で解放されることも保証します。 同様に、リソースの取得が失敗した (コンストラクタが例外を投げた) 場合は、完全に構築されたすべてのメンバおよび基底部分オブジェクトによって取得されたすべてのリソースが初期化の逆順で解放されます。 これはリソースリークを取り除き例外安全を保証するためにコア言語の機能 (オブジェクトの生存期間スコープの終了初期化の順序およびスタックの巻き戻し) を活用します。 このテクニックは、 RAII オブジェクトの生存期間がスコープを終了することによって終了する場合の基本的なユースケースにちなんで、スコープに縛られたリソース管理 (Scope-Bound Resource Management) (SBRM) とも言います。

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

  • 各リソースを以下のようなクラスにカプセル化します。
  • コンストラクタは、リソースを取得し、クラスのすべての不変条件を確立します。 または、それができない場合は例外を投げます。
  • デストラクタは、リソースを解放します。 例外を投げることはありません。
  • 必ず以下のいずれかのような RAII クラスのインスタンスを通してリソースを使用します。
  • 自動記憶域期間またはそれ自身の一時的な生存期間を持つ。 または、
  • 自動または一時オブジェクトの生存期間に縛られた生存期間を持つ。

ムーブセマンティクスは、リソースの安全性を維持しつつ、オブジェクト間で、スコープを超えて、およびスレッドの内外へ、リソースの所有権を安全に転送することを可能とします。

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::stringstd::vectorstd::thread およびその他多数) は、コンストラクタでリソースを取得し (エラーの場合は例外を投げ)、デストラクタでそれを解放し (例外を投げることはありません)、明示的なクリーンアップを要求しません。

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

[編集]ノート

RAII は、使用する前に取得しないリソース (CPU 時間、コア、キャッシュ容量、エントロピープールの容量、ネットワーク帯域、電力消費、スタックメモリなど) の管理には、適用されません。

[編集]参考文献

  1. RAII in Stroustrup's C++ FAQ
  2. C++ Core Guidelines E.6 "Use RAII to prevent leaks"
close