placement newとは
placement new(配置new)とは、newを呼び出す際の使用するメモリを呼び出す側で管理することができる機能です。
通常のnewを呼び出した場合、呼び出したタイミングで必要なメモリサイズを計算して確保してくれます。
ただ、このメモリ確保を自分で行って実装したい場面もあります。
そういった場合に使えるのがplacement newです。
ではplacement newを使用方法を見ていきましょう。
placement newの使い方
placement newを使う前に先ずは通常のnewでの確保と解放を見てみましょう。
今回は下記のHogeクラスを使った想定で記述していきます。
class Hoge { public: Hoge() { OutputDebugString("Hoge()\n"); } ~Hoge() { OutputDebugString("~Hoge()\n"); } };
通常のnew
void NormalNew() { // メモリの確保とコンストラクタの呼び出し Hoge* hoge = new Hoge(); // メモリの解放とデストラクタの呼び出し delete hoge; }
・出力結果
Hoge()
~Hoge()
このように通常のnewはメモリをどこからどれだけ確保するかを気にせずに使用することができます。
そしてdeleteを呼び出すことでメモリの解放まで行います。
placement new
// placement newの使用するにはnewヘッダーが必要 #include <new> void PlacementNew() { // メモリの確保 void* ptr = malloc(sizeof(Hoge)); // ptrに対してHogeクラスのインスタンス割り当て(コンストラクタの呼び出し) Hoge* hoge = new(ptr) Hoge(); // デストラクタの呼び出し hoge->~Hoge(); // メモリの解放 free(ptr); }
このようにplacement newを使う際はメモリの確保と解放を自前で行う必要があります。
そしてnewではインスタンスの割り当て(コンストラクタの呼び出し)を行っています。
又、placement newの場合、通常通りdeleteを呼び出してしまうとメモリの解放を行ってしまいます。
なので ~クラス名 という形で強制的にデストラクタのみを呼び出しています。
最後はメモリを解放して終わりです。
少し手間がかかりますね。
でも、こうやってメモリを自分で管理することによって柔軟にメモリを管理することができます。
最初のうちは必要性が分かりにくいですが、アロケーター(メモリ管理機能)の自作なんかを始めると多用するようになってきます。
他にもこんな使い方もあります。
void PlacementNew() { // スタックメモリの確保 char memory[sizeof(Hoge)]; // ptrに対してHogeクラスのインスタンス割り当て(コンストラクタの呼び出し) Hoge* hoge = new(memory) Hoge(); // デストラクタの呼び出し hoge->~Hoge(); }
プログラム上の変数としてクラスのサイズ分のメモリを用意して、そこにクラスのインスタンスを割り当てることができます。
こういった柔軟なメモリの使い方ができるのでメモリ管理の幅が広がってきます。
placement newは高速化などに使える場合もあるので色々と試してみると面白いかと思います。