C++のRAII
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 16/104。
RAII(Resource Acquisition Is Initialization)は、resource の管理を object のライフタイムに結び付ける、基本的な C++ のイディオムです。考え方は単純です。constructor で resource を取得し、destructor で解放します。
object が作成されると、必要なリソースをすべて取得します。object がスコープ外になると、その destructor が automatically それらのリソースを解放します。これにより、exception が発生した場合でもクリーンアップが保証されます。
class FileHandler {
std::FILE* file;
public:
FileHandler(const char* filename) {
file = std::fopen(filename, "r"); // リソースを取得
}
~FileHandler() {
if (file) std::fclose(file); // リソースを解放
}
};RAIIを使えば、クリーンアップを忘れることはありません。
void processFile() {
FileHandler handler("data.txt"); // リソースを取得
// ファイルを操作...
// ここで例外がスローされても、デストラクタは実行される!
} // リソースは自動的に解放されるスマートポインターは、RAIIが実際に機能している完璧な例です。unique_ptrはconstructorでヒープメモリの所有権を取得し、destructorでそれを削除します。あなたは気づかないうちに、すでにRAIIを使っていました!
RAII は、あらゆる resource に適用できます。メモリ、file ハンドル、ネットワーク接続、ミューテックス、またはデータベース接続などです。resource をオブジェクトでラップすることで、C++ は決定論的なクリーンアップを保証し、リークやダングリングハンドルのようなバグの種類全体を排除します。
チャレンジ
簡単RAIIによってネットワーク接続のような connection のライフサイクルを automatically 処理する connection manager を構築しましょう。connection が作成されると "open" し、スコープ外に出ると automatically "close" するようにします。手動のクリーンアップは不要です!
コードを整理するために、2つのファイルを作成します。
Connection.h:RAII の原則を使用して connection resource を管理するConnectionclass を define します。class には次の要素が必要です。- connection を識別するための private
connectionIdattribute(string) - connection の状態を追跡するための private
isOpenattribute(bool) - connection ID を受け取り、
isOpenを true に設定し、"Opening connection: <id>"を print する constructor - connection が open かどうかを確認し、
isOpenを false に設定して close し、"Closing connection: <id>"を print する destructor - connection が open の場合に
"[<id>] Sending: <message>"を print するsend(string message)method - connection ID を返す
getId()method
- connection を識別するための private
main.cpp:input から connection ID と message を読み取り、RAII によって cleanup が automatically 行われることを示します。次に:- curly braces
{ }を使用してスコープを作成する - そのスコープの Inside で、input ID を使って stack 上に
Connectionobject を作成する - connection を使用して input message を送信する
- スコープを end させる(connection は automatically close されるはずです)
- スコープの After に
"Connection out of scope"を print する
- curly braces
RAII のすばらしい点は、connection を close することを覚えておく必要がないことです。object がスコープを離れると、destructor が automatically 処理します。このパターンにより、コード内で予期しないことが起きた場合でも resource leak を防げます。
#include "Connection.h" を使用して、header file を main.cpp に include してください。
自分で試してみよう
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
string connectionId;
string message;
// 入力を読み取る
cin >> connectionId;
cin.ignore();
getline(cin, message);
// TODO: 波括弧 { } を使ってスコープを作成する
// スコープ内で:
// - connectionId を使ってスタック上に Connection オブジェクトを作成する
// - コネクションを使ってメッセージを送信する
// スコープを終了させる(デストラクタが自動的に呼び出される)
// TODO: After the scope ends, print "Connection out of scope"
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ