配列に使用する場合、移植可能なコードで新しい配置を実際に利用することは可能ですか?
new[] から返されるポインタは、渡したアドレスと必ずしも同じではないようです (5.3.4、標準の注記 12 は、これが正しいことを確認しているようです)。この場合、配列が入るバッファを割り当てることができます。
次の例は、問題を示しています。この例を Visual Studio でコンパイルすると、メモリが破損します。
#include <new>
#include <stdio.h>
class A
{
public:
A() : data(0) {}
virtual ~A() {}
int data;
};
int main()
{
const int NUMELEMENTS=20;
char *pBuffer = new char[NUMELEMENTS*sizeof(A)];
A *pA = new(pBuffer) A[NUMELEMENTS];
// With VC++, pA will be four bytes higher than pBuffer
printf("Buffer address: %x, Array address: %x\n", pBuffer, pA);
// Debug runtime will assert here due to heap corruption
delete[] pBuffer;
return 0;
}
メモリーを見ると、コンパイラーはバッファーの最初の 4 バイトを使用して、項目数のカウントを格納しているようです。これは、バッファーがsizeof(A)*NUMELEMENTS
大きいだけであるため、配列の最後の要素が未割り当てヒープに書き込まれることを意味します。
質問は、placement new[] を安全に使用するために、実装が必要とする追加のオーバーヘッドをどれだけ見つけられるかということです。理想的には、異なるコンパイラ間で移植可能な手法が必要です。少なくとも VC の場合、オーバーヘッドはクラスによって異なるように見えることに注意してください。たとえば、例で仮想デストラクタを削除すると、new[] から返されるアドレスは、渡したアドレスと同じになります。