Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

placement-new address vs raw memory address

The result of a placement new always seems to be the same as the memory pointer that I provide to the placement new. With GCC this seems to hold true even for classes with virtual functions, for example...

#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;
}

The output of this program is (note: 64 bit linux)...

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

Does C++ guarantee that mem and ptr are identical or is this just a GCC coincidence? In a larger portable program, will I have to preserve both mem and ptr or can I just preserve one of them and cast when needed?

To clarify the question a bit, I know that memory allocators will sometimes put the size of an allocated block in the word before the pointed to block of memory. Are C++ compilers allowed to use tricks like that and say put the VMT pointer in the word before the block of memory to which an object pointer points? In this case mem and ptr would be different.

like image 573
goertzenator Avatar asked Sep 17 '25 09:09

goertzenator


1 Answers

Yes, they're the same. You might like to think of a memory address as a void pointer and of an object address as a typed pointer, but if you like, you can cast. In some sense, new is the way to "convert" a memory address into an object (by constructing one). Here's the full picture (note how there are no casts):

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);

This is only true for the non-array version of new, though. Array-placement-new is different, and essentially unusable.

You might like to look at your implementation of std::allocator to see placement-new and casting in action.

like image 92
Kerrek SB Avatar answered Sep 18 '25 22:09

Kerrek SB