動的メモリ割り当てとは、実行中に必要な大きさのメモリを確保することだ。 C++ では、典型的にはヒープ上にオブジェクトを確保する形で行われる。

new

new は、メモリを確保し、その場所にオブジェクトを生成して、そのアドレスを返す。

int* ptr { new int };

初期値を与えることもできる。

int* ptr1 { new int(5) };
int* ptr2 { new int{6} };

配列を動的に確保する場合は new[] を使う。

int* data { new int[10]{} };

delete

new で確保したオブジェクトは delete で破棄し、new[] で確保した配列は delete[] で解放する。

delete ptr;
ptr = nullptr;
 
delete[] data;
data = nullptr;

delete は、オブジェクトのデストラクタ(C++)を呼んだあとで、そのメモリを解放する。

解放後のポインタを使うと危険なので、必要に応じて nullptr を代入しておくと誤用に気付きやすくなる。

失敗

動的メモリ確保に失敗すると、通常の newstd::bad_alloc 例外を送出する。

int* value { new int };

std::nothrow を使うと、例外の代わりに nullptr を返させることもできる。

#include <new>
 
int* value { new (std::nothrow) int };

メモリリーク

メモリリークとは、動的に確保したメモリを解放できなくなること。

int* ptr { new int{5} };
ptr = new int{6}; // 最初のメモリへの参照を失う

この例では、最初に確保した int へのポインタを上書きしてしまい、delete できなくなる。

補足

  • 動的メモリ割り当ては便利だが、new / delete を手で管理するとバグの原因になりやすい
  • 現代の C++ では、生ポインタを直接所有させるより、unique_ptrvector(C++) などの所有者型を使うことが多い
  • 動的に確保したオブジェクトは、自動変数のようにスコープを抜けただけでは自動解放されない

関連

参考