2012-05-14 2 views
5

C++の配置newの構文に関する質問があります。次の2つのコードスニペットは機能的に同等であり、互換的に使用できます(最初のものが適切な場合は、2番目のコードを使用することを意味しているわけではありません)。配置の新しい振る舞いは

#1

T* myObj = new T(); 
// Do something with myObj 
delete myObj; 

#2

char* mem = new char[sizeof(T)]; 
T* myObj = new (mem) T(); 
// Do something with myObj 
myObj->~T(); 
delete[] mem; 

私はこのような配置新しい構文を使用していたとき、私は、特に注意しなければならないものがありますか?

答えて

11

Tのコンストラクタまたはデストラクタがスローすると、動作が異なるため、これらは同等ではありません。

new T()は、例外をさらに伝播させる前に割り当てられたメモリを解放します。 char* mem = new char[sizeof(T)]; T* myObj = new (mem) T();は、あなたが明示的に何かをして解放されることを保証しない限り、あなたには漏れがあります。同様に、delete myObjは、~T()がスローするかどうかにかかわらず、常にメモリの割り当てを解除します。 T* myObj = new T();/*other code*/delete myObj;ため

、完全に同等ではのようになります。基本的なレベルで

//When using new/delete, T::operator new/delete 
//will be used if it exists. 
//I don't know how do emulate this in 
//a generic way, so this code just uses 
//the global versions of operator new and delete. 
void *mem = ::operator new(sizeof(T)); 
T* myObj; 
try { 
    myObj = new (mem) T(); 
} 
catch(...) { 
    ::operator delete(mem); 
    throw; 
} 
/*other code*/ 
try { 
    myObj->~T(); 
    ::operator delete(mem); 
} 
catch(...) { 
    //yes there are a lot of duplicate ::operator deletes 
    //This is what I get for not using RAII): 
    ::operator delete(mem); 
    throw; 
} 
+0

'new char [sizeof(T)] 'によって割り当てられたメモリは適切に整列されますか? –

+3

@ TadeuszKopec:標準では、メモリが最大限の位置合わせを保証しています。これは、プラグインを使用して型の整列を例えば最大値の2倍にバンプしてからすべてのベットをオフにすると、自然な整列(つまり、組み込み型で表示される)を使用する場合にのみ有効です。 –

8

あなたは生のメモリを割り当てるしているので、近い同等は次のようになります。あなたが特定のクラスのための::operator newを過負荷にした場合、これはあなたがnew char []を使用して、そのクラスのoperator newを、使用すること

void *mem = operator new(sizeof(T)); 
T *myobj = new(mem) T(); 

// ... 

myobj->~T(); 
operator delete(mem); 

注意それを無視するだろう。

編集:ここに例外の可能性を無視していると付け加えておきますが、 @ Mankarseの答えは、かなりうまくその部分をカバーするよう(私に)思われる。

0

、あなたはどちらの状況で同じことをやっている:あなたはヒープ上に新しいオブジェクトをインスタンス化している、すなわち、メモリを解放しますが、後者の場合、あなたは(明らかに)配置new演算子を使用しています。

この場合、Mankarseが説明したようにコンストラクタがスローすると、両方の結果が同じ結果になります。

さらに、第2のケースはどのように現実的な例ではないので、それらを同じ意味で使用できるとは言いません。placement newが使用されています。おそらくメモリプールのコンテキストでplacement newを使用するのはずっと意味があります。自分のメモリマネージャを書くなら、割り当てられたメモリに複数のTオブジェクトを置くことができます(私のテストでは、 25%のCPU時間)。 placement newのより現実的なユースケースをお持ちの場合は、さらに心配すべきことがたくさんあります。

0

さて、Tオブジェクトのメモリをあらかじめ割り当てています。そしてそれはうまくいくはずです。それでも、割り当てられた領域をもう一度再利用すると意味があります。それ以外の場合は遅くなります。

0

はい。あなたの例はこれを実証するのは簡単すぎますが、あらかじめ割り当てられたメモリ "mem"は、 "myObj"内に格納されているオブジェクトを管理する必要があります。「

することはおそらくシナリオ#1は、ヒープ上のスペースを割り当て、その空間内のオブジェクトを構築し、より良い方法を置く。シナリオ#2は、ヒープ上のスペースを割り振り、 『MEMは、』そのオブジェクトを構築しますどこかその空間内。

は今、内どこか別の場所第2の目的を置く「MEM。」それは右?

建設との両方のシナリオで同じ起こっているこのmyobjの破壊(を除いて、複雑になりますC Mankarseによって指摘されているように例外をスローするコンストラクタのase)が、シナリオ#1ではなく、シナリオ#2であなたのメモリ管理を担当しています。

したがって、「mem」を適切に管理するように注意してください。 1つのcommon approachは次の通りです:

template<class T> void destroy(T* p, Arena& a) 
{ 
     if (p) { 
       p->~T();  // explicit destructor call 
       a.deallocate(p); 
     } 
}