4

C ++で所定の場所にあるオブジェクトの構築の使用は何ですか?

次のコードは、所定の場所での建設を示しています-

void *address = (void *) 0xBAADCAFE ;
MyClass *ptr = new (address) MyClass (/*arguments to constructor*/) ;

これにより、最終的に、所定の「アドレス」に MyClass のオブジェクトが作成されます。(アドレスが指すストレージがMyClass オブジェクトを保持するのに十分な大きさであると仮定します)。

このようなメモリ内の所定の場所にオブジェクトを作成する方法を知りたいです。

4

5 に答える 5

2

主に次の 2 つの場合があります。

1 つ目は、組み込みシステムなどで、既知の場所にオブジェクトを構築する必要がある場合です。

2 つ目は、何らかの理由で、デフォルト以外の方法でメモリを管理したい場合です。

C++ では、式 likepA = new(...) A(...)は次の 2 つの連続した処理を行います。

  1. 関数を呼び出し、void* operator new(size_t, ...)その後
  2. を呼び出しますA::A(...)

new の呼び出しは A::A() を呼び出す唯一の方法であるため、パラメーターを new に追加すると、メモリを管理する別の方法を特殊化できます。最も些細なことは、「他の手段ですでに取得したメモリを使用する」ことです。

この方法は、割り当てと構築を分離する必要がある場合に適しています。典型的なケースはstd::allocatorで、オブジェクトの構築は後で行われますが、その目的は特定の量の初期化されていないメモリを割り当てることです。

これは、たとえば で発生します。これは、通常、実際の よりも広いstd::vectorを割り当ててから、既に存在するスペースでオブジェクトを構築する必要があるためです。capacitysizepush_back

実際、デフォルトの std::allocator 実装では、n オブジェクトを割り当てるように要求すると、 が実行されるreturn reinterpret_cast<T*>(new char[n*sizeof(T)])ため、スペースが割り当てられますが、実際には何も構築されません。

std::vector ストアを認めること:

T* pT;  //the actual buffer
size_t sz; //the actual size
size_t cap; //the actual capacity
allocator<T> alloc;

push_back の実装は次のとおりです。

void vector<T>::push_back(const T& t)
{
   if(sz==cap)
   {
       size_t ncap = cap + 1+ cap/2; //just something more than cap 
       T* npT = alloc.allocate(ncap); 
       for(size_t i=0; i<sz; ++i) 
       {
          new(npT+i)T(pt[i]); //copy old values (may be move in C++11)
          pt[i].~T(); // destroy old value, without deallocating
       }
       alloc.deallocate(pt,cap);
       pT = npT; 
       cap = ncap;
       // now we heve extra capacity       
   }
   new(pT+sz)T(t); //copy the new value
   ++sz; //actual size grown
}

本質的に、割り当て (バッファ全体に関連する) と要素の構築 (既存のバッファで発生する必要がある) を分離する必要があります。

于 2012-04-04T07:09:00.533 に答える
2

プレースメント new が役立つ 1 つのシナリオは次のとおりです。

一度大きなバッファを事前に割り当ててから、多くの配置new演算子を使用できます。
これにより、パフォーマンスが向上し (毎回再割り当ては必要ありません)、断片化されたメモリが少なくなります (小さなメモリ チャンクが必要な場合)。通常、これはstd::vector実装で使用されるものです。

欠点は、割り当てられたメモリを手動で管理する必要があることです。配置によって割り当てられたオブジェクトnewは、必要がなくなったら、明示的なデストラクタの呼び出しが必要です。

事前最適化のために新しい配置に移動するのではなく、ボトルネックについてアプリケーションをプロファイリングすることを常にお勧めします。

于 2012-04-04T07:09:06.767 に答える
1

通常、一部のハードウェアが特定のアドレス範囲を介してアドレス指定される、埋め込みコードまたはドライバーコードの所定の場所を使用します。

ただし、この場合、そのアドレスのストレージはアクセスに使用されないか、意図されていません(または、新しいオペレーターがそれを使用していることがわからないため、使用する必要はありません)。操作が実行されます。

これを初期化値として使用します(newでは実際には変更されません)。私の頭に浮かぶ目的は2つあります。1つは、後で新しいものを忘れた場合に備えて、デバッガーにマジックアドレス(この場合は0xBAAADCAFE)がすぐに表示されることです。

次に、新しい演算子をいじってinit値が必要な場合に使用できるので、デバッグできます(たとえば、変更を確認できます)。

または、新しい演算子を変更して、そのマジックナンバーで何でもできるようにしました(たとえば、デバッグに使用したり、上記のように、特定のハードウェアの特定のアドレスで実際にメモリを使用したりできます)、異なる割り当て方法を切り替えます。 ..。。

編集:この場合に正しく答えるには、新しい演算子が実際に何をするかを確認する必要があります。そのニュースソースコードを確認する必要があります。

于 2012-04-04T06:45:48.473 に答える
0

この特定の動作は、長いDWORD、DWORD_PTR、またはその他のサイズのポインターを関数の引数として渡してクラスのアドレスを知っていて、OOで使用するためにクラスのコピーを再構築する必要がある場合に役立ちます。

または、これを使用して、事前に割り当てられたメモリまたは静的であると判断した場所にクラスを作成することもできます(つまり、アプリケーションをいくつかの古いASMライブラリにリンクしています)。

于 2012-04-04T06:45:23.753 に答える
0

カスタム アロケータ、リアルタイム (ここではロックなし)、およびパフォーマンス。

于 2012-04-04T07:08:32.007 に答える