ikautak.log

C/C++, Python, CUDA, Android, Linux kernel, Network, etc.

More Effective C++ 項目9 リソースリークを防ぐためにデストラクタを使う

新訂版 More Effective C++ (AddisonーWesley professional co)

新訂版 More Effective C++ (AddisonーWesley professional co)

  • 作者: スコット・メイヤーズ,安村通晃,伊賀聡一郎,飯田朱美,永田周一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2007/06/29
  • メディア: 単行本(ソフトカバー)
  • 購入: 8人 クリック: 129回
  • この商品を含むブログ (43件) を見る

項目9 リソースリークを防ぐためにデストラクタを使う

メモリを確保した後、解放するまでの間の例外は、リソースリークの危険がある。

void function(istream& dataSource) {
    while (dataSource) {                      // データがある間、
        Sample* ps = readSample(dataSource);  // readして、
        ps->process();                        // 処理して、
        delete ps;                            // 削除する。
    }
}

この場合、process()で例外が発生すると、deleteが実行されず、リソースリークしてしまう。
try/catchで書きなおすと以下のようになる。

void function(istream& dataSource) {
    while (dataSource) {
        Sample* ps = readSample(dataSource);
        try {
            ps->process();
        } catch (...) {    // 例外を受け取る
            delete ps;     // 例外発生時、リソースリークを防ぐ
            throw;         // 例外を伝搬させる
        }

        delete ps;         // 例外が発生していないとき、リソース解放
    }
}

この方法だと、正常なパスと例外発生時のパスの両方にクリーンアップコードを書かなければならない。

自動的に破棄させるためにはスマートポインタを使う。
C++にはauto_ptrというクラステンプレートが含まれていて、それを使えば以下のようになる。

void function(istream& dataSource) {
    while (dataSource) {
        auto_ptr<Sample> ps(readSample(dataSource));  // readして、auto_ptrに入れる
        ps->process();
    }
}

これでスコープから外れてauto_ptrのデストラクタが呼ばれたとき、リソースが解放される。

まとめ
リソースをオブジェクトの中にカプセル化し、デストラクタで解放すればリソースリークを通常は回避できる。
コンストラクタでの例外や、リソースの自動破棄の最中の例外はこの後の項目で出てくる。