主に次の 2 つの場合があります。
1 つ目は、組み込みシステムなどで、既知の場所にオブジェクトを構築する必要がある場合です。
2 つ目は、何らかの理由で、デフォルト以外の方法でメモリを管理したい場合です。
C++ では、式 likepA = new(...) A(...)
は次の 2 つの連続した処理を行います。
- 関数を呼び出し、
void* operator new(size_t, ...)
その後
- を呼び出します
A::A(...)
。
new の呼び出しは A::A() を呼び出す唯一の方法であるため、パラメーターを new に追加すると、メモリを管理する別の方法を特殊化できます。最も些細なことは、「他の手段ですでに取得したメモリを使用する」ことです。
この方法は、割り当てと構築を分離する必要がある場合に適しています。典型的なケースはstd::allocator
で、オブジェクトの構築は後で行われますが、その目的は特定の量の初期化されていないメモリを割り当てることです。
これは、たとえば で発生します。これは、通常、実際の よりも広いstd::vector
を割り当ててから、既に存在するスペースでオブジェクトを構築する必要があるためです。capacity
size
push_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
}
本質的に、割り当て (バッファ全体に関連する) と要素の構築 (既存のバッファで発生する必要がある) を分離する必要があります。