Menu
Coddy logo textTech

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++ は決定論的なクリーンアップを保証し、リークやダングリングハンドルのようなバグの種類全体を排除します。

challenge icon

チャレンジ

簡単

RAIIによってネットワーク接続のような connection のライフサイクルを automatically 処理する connection manager を構築しましょう。connection が作成されると "open" し、スコープ外に出ると automatically "close" するようにします。手動のクリーンアップは不要です!

コードを整理するために、2つのファイルを作成します。

  • Connection.h:RAII の原則を使用して connection resource を管理する Connection class を define します。class には次の要素が必要です。
    • connection を識別するための private connectionId attribute(string)
    • connection の状態を追跡するための private isOpen attribute(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
  • main.cpp:input から connection ID と message を読み取り、RAII によって cleanup が automatically 行われることを示します。次に:
    • curly braces { } を使用してスコープを作成する
    • そのスコープの Inside で、input ID を使って stack 上に Connection object を作成する
    • connection を使用して input message を送信する
    • スコープを end させる(connection は automatically close されるはずです)
    • スコープの After に "Connection out of scope" を print する

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;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C++オンラインコンパイラ