C++

newしたポインタのvectorをスコープ外からdeleteする方法

はじめに

データ容量の大きめのクラスをvectorに格納する場合、インスタンスをvectorに格納していくと、メモリを確保しなおす場合や、push_backの際にコピーするのに時間がかかっていまう。

そこで、インスタンスではなくpointerをvectorに格納しておく方法が良い。
newによってクラスのメモリ領域を確保した場合、deleteによってメモリの解放をする必要がある。
しかし、newした作成したスコープを抜けてしまった場合にメモリの解放の仕方がわからなく、調べてわかったことをメモ。

問題のコード

デストラクタなどは今回は無視します。

// 使用するクラス
class Hoge {
public:
    Hoge(int _hoge);
    void get();
private:
    int hoge;
}

Hoge::Hoge(int _hoge) {
    hoge = _hoge;
}

void Hoge::get() {
    return hoge;
}

// main文
int main(int argc, char* argv[]) {
    // Hogeポインタのvector
    std::vector<Hoge*> vecHoge;

    for (int i = 0; i < 10; ++i) {
        // newでメモリ確保
        Hoge* tmp = new Hoge(i);
        // vectorにpointerを格納
        vecHoge.push_back(tmp);

        //==============================================================//
        // tmpがスコープから外れてしまうので。これ以降のメモリ解放ができない。//
        // しかし、ここでtmpのメモリを解放してしまうと、                    //
        // このあとでvecHogeからインスタンスにアクセスできない。            //
        //==============================================================//
    }

    for (int i = 0; i < vecHoge.size(); ++i) {
        std::cout << vecHoge[i].get() << std::endl;
    } 

    //==========================//
    // ここでメモリの解放をしたい //
    //==========================//

    return 0;
}

解決策

実はすごく簡単な話だった。

// 使用するクラス
class Hoge {
public:
    Hoge(int _hoge);
    void get();
private:
    int hoge;
}

Hoge::Hoge(int _hoge) {
    hoge = _hoge;
}

void Hoge::get() {
    return hoge;
}

// main文
int main(int argc, char* argv[]) {
    // Hogeポインタのvector
    std::vector<Hoge*> vecHoge;

    for (int i = 0; i < 10; ++i) {
        // newでメモリ確保
        Hoge* tmp = new Hoge(i);
        // vectorにpointerを格納
        vecHoge.push_back(tmp);
    }

    for (int i = 0; i < vecHoge.size(); ++i) {
        std::cout << vecHoge[i].get() << std::endl;
    } 

    // vectorにpointerは入ったままなので、ここで一つずつdeleteすれば良い
    for (int i = 0; i < vecHoge.size(); ++i) {
        delete vecHoge[i];
    }

    return 0;
}

一応、何度もこれを書くのは面倒な気がしたので、関数化するといいかもしれません。

void releaseMemory(std::vector<Hoge*>& vecHoge) {
    for (int i = 0; i < vecHoge.size(); ++i) {
        delete vecHoge[i];
    }
}

追記(2017/10/02)

コメントいただいた部分に関して追記いたします。

  1. deleter
    終盤に書かせていただいたメモリ開放をする関数をC++では一般に"deleter"と呼ばれるらしく、このdeleterをデストラクタに書くと良いとのことです。

  2. スマートポインタ
    std::unique_ptrやstd::shared_ptrなどのスマートポインタを使用することでいちいちこんなことをしなくて良いようです。
    こちらは別記事にまとめましたので、そちらをご覧ください。
    コメントいただきありがとうございました。