placement newは、C++における特別な形のnew演算子です。指定されたアドレスに既に確保されたメモリ領域にオブジェクトを配置することを可能にします。通常、手動メモリ管理のために使用され、アロケータやオブジェクトプーリング、固定バッファへのシリアル化の基盤となります。
構文:
#include <new> void* memory = malloc(sizeof(MyClass)); MyClass* obj = new (memory) MyClass(args...); // memoryのアドレスでコンストラクタを呼び出す
ここでは、メモリは別途(たとえば、mallocやアロケータを通じて)確保され、その後にクラスのコンストラクタがこのメモリで呼び出されます。デストラクタを明示的に呼び出すことを忘れないでください:
obj->~MyClass(); free(memory);
利点:
'placement new'を使用して同じメモリブロックに複数のオブジェクトを連続して配置することは可能ですか?その結果はどうなりますか?
一般的な誤解は、以前の状態に気を配らずに新しいオブジェクトをメモリに配置できるということです。実際には、同じメモリ領域に新しいオブジェクトを古いオブジェクトの上に配置すると、デストラクタを呼び出さなかった場合、リソースリークが発生し、その後のデストラクタの呼び出しは未定義動作(UB)を引き起こします。
例:
void* place = malloc(sizeof(A)); A* a = new (place) A(); B* b = new (place) B(); // オブジェクトAは破壊されていない! UB!
物語
高負荷のシステムで、開発者は
malloc+placement newを介してオブジェクトプールを実装しましたが、プールにオブジェクトを返す際にデストラクタを呼び出すことを忘れました。その結果、リソース(オブジェクト内のシステム記述子)が解放されず、リークとサーバーの「ハング」に繋がりました。
物語
バイナリデータのシリアル化のためのプロジェクトでは、バッファと
placement newを使用してオブジェクトをその場でデコードしました。しかし、配置する前にメモリをゼロで初期化することを忘れ、初期化されていないデータを読み取ったり、POD構造体で奇妙なバグが発生しました。
物語
あるモジュールは、事前に確保されたブロック内で
placement newを使用してオブジェクトの配列を配置するように移行しました。クラス内に新しいメンバーを追加した後、非自明なデストラクタを持つため、プログラムが異常終了することになりました — クリーンアップ時に各要素のデストラクタを明示的に呼び出す必要があることを忘れていました。