下記のコードにCPPCHECKを実施すると『Mismatching allocation and deallocation』というエラーを出力する。WarningではなくErrorなので重い。
void main(void) { float *sn = new float[100]; delete sn; return; }
snはfloat型の配列なのでdelete[]とすれば、CPPCHECKのエラーは解消されるが、deleteとdelete[ ]で解放の動作が違うのか気になったのでVS2015のヒープスナップショットを使ってdelete前後のヒープサイズを比較してみた。
図1. deleteを使った場合
図2. delete[ ]を使った場合
結果:"delete"と”delete[ ]”どちらも変わらず、ちゃんと解放されている(何故?理由は後述)
疑問:"delete"と”delete[ ]″に違いは何か?
というわけで、deleteとdelete[ ]の違いをぐぐってみたところ下記のブログに答えが書いてあった。
プログラミングメモ日記 C++ の delete と delete[] の違い
つまり、deleteは配列オブジェクトの先頭要素のデストラクタしか呼ばない。delete[ ]は配列の全要素のデストラクトを呼ぶ。floatみたいなプリミティブ型の変数はデストラクタやコンストラクタを持っていないので差が出ない(たぶん)。
というわけで下記のようにクラス型の変数で先ほどと同様の実験をしてみた。
class cTest { public: cTest() { m_x = 1000; m_y = 200; }; ~cTest() {}; int m_x; int m_y; }; void main(void) { cTest *sn = new cTest[100]; delete sn; return; }
このコードをVS2015でデバッグビルドで実行したところ、メモリアロケーション発生(TT)
リリースビルドだと一応動かすことができた。しかしヒープを見ると領域が解放されておらず、メモリリークしている。
snの開放をdelete[ ]に変えたところ、問題なく実行できた。配列の全要素がちゃんと解放されている。
■まとめ
deleteとdelete[ ]はデストラクタの呼び出しが異なる。配列を持つオブジェクトはdelete[ ]を使わないとメモリリークの原因となる。
デストラクタを持つクラスや構造体等のオブジェクト型じゃないとdeleteとdelete[ ]の差はない。