2012-03-11 35 views
3

放置新的結果總是似乎與我提供給放置新的內存指針相同。隨着GCC這似乎是正確的,即使與虛擬功能,如類...放置 - 新地址vs原始內存地址

#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

是的,它們是一樣的。您可能想將內存地址視爲空指針,將對象地址視爲類型指針,但如果您願意,您可以投射。在某種意義上,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與此不同,essentially unusable

您可能會喜歡看看std::allocator的實現,以查看放置新行爲和施放行爲。

1

您正在使用void* operator new (std::size_t size, void* ptr) throw();版本的new運算符。以下是cplusplus.com對此運算符的說明:

這是放置版本,它不分配內存 - 它只是返回ptr。注意,雖然對象的構造函數(如果有的話)仍然會被運算符表達式調用。

因此,這意味着MEMPTR將永遠是相同的。 我認爲把它們都保留下來並且使用new運算符的void* operator new (std::size_t size) throw (std::bad_alloc);版本更好。在你的情況下:A* ptr = new A;;

+0

這是一個很好的答案,但它有多權威?它是基於標準還是特定編譯器的實現? – goertzenator 2012-03-11 22:25:54

+0

@goertzenator在C++標準中定義了3個'new'操作符。我建議你是C++程序中最常用的一個。請參閱[這裏](http://cplusplus.com/reference/std/new/operator%20new/)瞭解完整的文檔和使用示例。 – 2012-03-12 17:53:59