C++ では new をすると、operator new, operator delete でも実装していない限りは、必ず delete をする必要があります。
Hoge* pHoge = new Hoge();
...
delete pHoge;
普通に new をして領域を確保し、必要が無くなれば delete をするだけのプログラムです。
が、これだけでは必ず delete が出来るという保証はないのです。
これは例外について対処が出来ていなくて、pHoge を使っている途中に例外が発生した場合、pHoge は解放される機会を失い、メモリリークを引き起こします。
なので、次のように書く必要があります。
Hoge* pHoge = new Hoge();
try
{
...
}
catch (...)
{
delete pHoge;
throw;
}
delete pHoge;
こうすれば、pHoge を使っている途中で例外が発生しても、pHoge がリークすることは無くなります。
また、理論的には delete で例外が発生する可能性もあるのですが、これは C++ では決してやってはいけないことの一つなので、この可能性は除外します。
次は2つのオブジェクトを使用する場合について考えてみます。
Hoge* pHoge = new Hoge();
Hoge2* pHoge2 = new Hoge2();
try
{
...
}
catch (...)
{
delete pHoge;
delete pHoge2;
throw;
}
delete pHoge2;
delete pHoge;
これは最初のプログラムと同じような書き方ですが、これではダメです。
なぜなら、Hoge2 のオブジェクトを new する段階で例外が発生する可能性があり、そこで発生した場合は pHoge がリークを起こしてしまいます。
なので、次のようなプログラムになります。
Hoge* pHoge = new Hoge();
try
{
Hoge* pHoge2 = new Hoge2();
try
{
...
}
catch (...)
{
delete pHoge2;
throw;
}
delete pHoge2;
}
catch (...)
{
delete pHoge;
throw;
}
delete pHoge;
try, catch がネストして見づらくなってしまってますね。
じゃあ配列を使う場合はどうなるか。
Hoge* pHoges[10];
try
{
for (int i = 0; i < 10; i++)
{
pHoges[i] = new Hoge();
}
...
}
catch (...)
{
for (int i = 9; i >= 0; i--)
{
delete pHoges[i];
}
throw;
}
for (int i = 9; i >= 0; i--)
{
delete pHoges[i];
}
pHoges の初期値は不定です。例えば pHoges[7] = new Hoge(); の時に例外が発生した場合、pHoges[8] と pHoges[9] の値は不定になり、不定な値を delete しようとしているので、結果もまた不定です。
なので、次のように書く必要があります。
Hoge* pHoges[10];
for (int i = 0; i < 10; i++)
{
pHoges[i] = NULL;
}
try
{
for (int i = 0; i < 10; i++)
{
pHoges[i] = new Hoge();
}
...
}
catch (...)
{
for (int i = 9; i >= 0; i--)
{
delete pHoge[i];
}
throw;
}
for (int i = 9; i >= 0; i--)
{
delete pHoge[i];
}
最初に NULL で初期化しているのがポイントですね。
ちなみに NULL に対する delete は何もしないようにしなければならないという C++ の規定があるので、NULL チェックは行う必要はありません。
また、当たり前ですがこれらのプログラムは全て、途中で return してはいけません。
確実に delete されるように細心の注意が必要です。
さあみんな、こんな風に例外に対処して必ず delete を行うようにしましょう!
……とはいいませんw
当たり前ですが、new をする場合はスマートポインタを使うようにしましょう。
スマートポインタは多くの(時には頭痛がするぐらいの)問題を持ち込みますが、それでも↑のようなプログラムを書くよりはマシだと思います。
boost::shared_ptr<Hoge> hoge = boost::shared_ptr<Hoge>(new Hoge());
boost::shared_ptr<Hoge2> hoge2 = boost::shared_ptr<Hoge2>(new Hoge2());
...
便利便利ヽ(´ー`)ノ