動的メモリ割り当てとは、実行中に必要な大きさのメモリを確保することだ。 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 を代入しておくと誤用に気付きやすくなる。
失敗
動的メモリ確保に失敗すると、通常の new は std::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_ptr や vector(C++) などの所有者型を使うことが多い
- 動的に確保したオブジェクトは、自動変数のようにスコープを抜けただけでは自動解放されない