どうやら、placement new
事前に割り当てられたメモリに新しいオブジェクトを作成するので、時間がかからないということですか?古い通常のを使用して割り当てるよりも高速であるように見えnew
ます。それなら、これがとても便利で速いなら、placement new
いつも使ってみませんか?
6 に答える
通常(非配置)new
は基本的に行うことと同等です
T* ptr = static_cast<T*>(malloc(sizeof(T)));
new(ptr) T;
もちろん、エラーチェックなどによって現実は少し異なりますが、結果はほぼ同じです(同一ではないdelete
ため、そのようにポインタを割り当てることはできません。代わりに、デストラクタを明示的に呼び出す必要があります(ptr->~T()
)。を使用してメモリを解放しますfree
。
したがって、新しい配置は、メモリを割り当てる必要がないため、新しい配置以外よりも実際に高速である必要があります。ただし、問題は、メモリをどこかに割り当てる必要があることです。new
つまり、基本的に、1つの呼び出しをへの呼び出しとどこかに割り当てるためのコードに置き換えましplacement new
た(そうでない場合は、そもそもなぜ使用するのでしょうnew
か?)。これはあまり便利ではなく、バグが発生しやすいことは明らかです。
もちろん、より高速な割り当て方法を作成することもできますが、そのためには通常、何らかのトレードオフを行う必要があります。より多くのメモリ(空きブロックの識別を高速化するための追加データ)または非常に具体的なもの(単一のオブジェクトサイズの高速割り当ての書き込みは一般的なものよりもはるかに簡単)を使用しないと、より高速なアロケータを作成するのは簡単ではありません。結局、それは通常、努力する価値がありません(すでに行われている可能性が高い努力に値するシナリオの場合、既存のアロケータを使用できます(内部で新しい配置を使用する可能性があります))。
もちろん、新しい配置の使用法はありますが(メモリが事前に割り当てられている場合もあります)、それは一般的なケースではありません。
ほとんどのプログラムでは、使用パターンによって必要にならないため、これは単に不要です。ヒープをあまり使用しないプログラムでは違いはなく、正しく実行するのは困難です(つまり、オペレーティングシステムよりも優れています)。また、割り当てを最適化することによってのみ、多くを得ることができます。ほとんどの場合、アルゴリズムによる最適化により、全体的なスピードアップが大幅に向上します。カスタマイズされたアロケータが提供できる多くの保証(事前に割り当てられたメモリを介した割り当ての保証された時間制限、低メモリの断片化)は、多くの場合必要ありません。
確かに、メモリ管理自体を行うことで利益を得ることができるプログラムがありますが、それらを特定するのは困難です。メモリ割り当てが実際にはボトルネックであることがわかった後は、より適切な割り当てスキームを見つけるのはさらに困難です。それがすべて行われたとしても、それでも面倒なことをする価値はありません。
new配置の目的の1つは、カスタムアロケータを使用して新しいオブジェクトを作成し、それらのコンストラクターを呼び出すことです。カスタムアロケータと同じくらい速いので、常に速いとは限りません。
このステップで実際にメモリを割り当てることを回避するため、メモリ内の特定の場所にオブジェクトを配置するために使用される新しい配置では、時間がかからない場合があります。
ただし、それ以前のある時点で割り当てられている必要があり、その前におそらく時間がかかります。事前に割り当てられたメモリにオブジェクトを配置する理由が実際にある場合は、これを使用するのが理にかなっています。
これは、この種の新しい演算子の1回の使用ではありません。詳細はこちら。
また、新しい配置ではデストラクタが自動的に呼び出されないことに注意してください。あなたはあなたfoo->~Foo();
のためにFoo foo;
手動でしなければなりません。
新しい配置によって割り当てが測定可能に速くなることがわかった唯一の場所は、寿命が限られている同じサイズのオブジェクトが多数あり、それらが頻繁に割り当てられて破棄される場合です。このタイプの動作を保証できない場合は、デフォルトの新しい実装を使用することをお勧めします。
同じサイズのオブジェクトを多数必要とするアプリケーションでは、プール(またはバルク)の割り当てが大幅に高速化されることがよくあります。基本的には、そのオブジェクトの多くに大きなバッファー(またはページ)を割り当て、オブジェクトが要求されたときにそのオブジェクト内で新しい配置を呼び出します。これにより処理速度が大幅に向上しますが、ほとんどのプログラムでは実際には必要ありません。
本当にそれを必要としないプログラムに対してこれを行おうとすると、おそらく最小限のスピードアップしか得られませんが、デバッグに多くの時間を費やす可能性があります。
だから本当にあなたが必要なものを見てください。同じオブジェクトを大量に割り当てる場合は、はい、新しい配置の方が速くなる可能性があります。しかし、ほんの少しのオブジェクト?気にしない。
しかし、それは必ずしも時間の問題ではありません。たとえば、新しい配置を使用して、ヒープ上のオブジェクトの配置を保証できます。あなたは次のようなことをすることができます:
void* buffer = aligned_malloc(sizeof(Object), 16);
Object* object = new (buffer) Waypoint();
これは、フロート配列などの一部のタイプがSSE関数およびレジスタで使用される場合に必要です。