3

配置 new の結果は常に、配置 new に提供するメモリ ポインターと同じように見えます。GCCでは、これは仮想関数を持つクラスにも当てはまるようです。たとえば...

#include <iostream>
#include <vector>

using namespace std;

class A
{
public:
    int a;
    virtual ~A() {}
};

int main()
{
    void *mem = malloc(sizeof(A));
    A* ptr = new(mem) A();

    cout << "sizeof(T) = " << sizeof(A) << endl;
    cout << "mem = " << mem << endl;
    cout << "ptr = " << ptr << endl;
    cout << "addr a = " << &(ptr->a) << endl;

    ptr->~A();
    free(mem);

    return 0;
}

このプログラムの出力は (注: 64 ビット Linux)...

sizeof(T) = 16
mem = 0x1a41010
ptr = 0x1a41010
addr a = 0x1a41018

C++ は mem と ptr が同一であることを保証しますか、それとも GCC の偶然の一致ですか? 大規模な移植可能なプログラムでは、mem と ptr の両方を保存する必要がありますか、それともどちらか一方だけを保存して必要に応じてキャストできますか?

質問を少し明確にするために、メモリ アロケーターは、割り当てられたブロックのサイズを、ポイントされたメモリ ブロックの前の単語に入れることがあることを知っています。C++ コンパイラは、そのようなトリックを使用して、オブジェクト ポインタが指すメモリ ブロックの前の単語に VMT ポインタを配置することを許可されていますか? この場合、mem と ptr は異なります。

4

2 に答える 2

5

はい、同じです。メモリ アドレスを void ポインターと考え、オブジェクト アドレスを型付きポインターと考えたいと思うかもしれませんが、必要に応じてキャストすることもできます。ある意味でnewは、メモリアドレスをオブジェクトに「変換」する方法です(オブジェクトを構築することにより)。全体像は次のとおりです(キャストがないことに注意してください):

void * addr = std::malloc(sizeof(T));  // or ::operator new(sizeof(T))
T * p = ::new (addr) T;                // "new" gives you an object pointer
p->~T();
std::free(addr);

ただし、これは の非配列バージョンにのみ当てはまりnewます。Array-placement-new は異なり、本質的に unusableです。

の実装を見て、std::allocatorplacement-new とキャストの動作を確認することをお勧めします。

于 2012-03-11T18:51:21.923 に答える
1

オペレーターvoid* operator new (std::size_t size, void* ptr) throw();のバージョンを使用しています。この演算子についてcplusplus.comnewが述べていることは次のとおりです。

これは、メモリを割り当てない配置バージョンです。単に ptr を返します。ただし、オブジェクトのコンストラクター (存在する場合) は引き続き演算子式によって呼び出されることに注意してください。

これは、memptrが常に同じであることを意味します。両方を保持するのは悪い考えだと思います。たとえば、あなたの場合は、void* operator new (std::size_t size) throw (std::bad_alloc);バージョンの演算子を使用することをお勧めします。newA* ptr = new A;

于 2012-03-11T19:44:02.967 に答える