2012-03-11 36 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