4

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.

goertzenator
  • 1,960
  • 18
  • 28

2 Answers2

5

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.

Community
  • 1
  • 1
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

You're using void* operator new (std::size_t size, void* ptr) throw(); version of new operator. Here is what cplusplus.com says about this operator:

This is the placement version, that does not allocate memory - it simply returns ptr. Notice though that the constructor for the object (if any) will still be called by the operator expression.

So this means that mem and ptr will always be the same. I think it's bad idea to keep both of them and it's better to use void* operator new (std::size_t size) throw (std::bad_alloc); version of new operator, e.g. in your case: A* ptr = new A;;

  • That's a good answer, but how authoritative is it? Is it based on a standard or the implementation of a particular compiler? – goertzenator Mar 11 '12 at 22:25
  • @goertzenator There are 3 versions of `new` operator defined in the C++ standard. The one I suggested you is the most common one used in C++ programs. Please refer [here](http://cplusplus.com/reference/std/new/operator%20new/) for full documentation and examples of their usage. – Artak Begnazaryan Mar 12 '12 at 17:53