Question

I created some custom memory allocators based on the code found in this gamedev.net post.

One of the utility templates described in the article is declared like so:

template <class T> T* allocateNew(Allocator& allocator, T& t) {
    return new (allocator.allocate(sizeof(T), alignof(T))) T(t);
}

* I converted __alignof() to calls to alignof() ones because I'm using C++11

I think that this code allocates memory for a new T object, copies the t stack object from a reference to the freshly-allocated heap memory and returns the T* pointer to the new object.

With this assumpions I converted the code above to this:

template <class T> T* allocateNew(Allocator& allocator, T& t) {
    void *ptr = allocator.allocate (sizeof (T), alignof (T));
    assert(ptr && "So that I don't dereference a null pointer");
    * (T *) (ptr) = instance; // Casting void* to T* and then dereferencing
    return (T *) ptr;
}

It seems to be working just fine. My questions are:

  • Does new do anything different than the void pointer casting does?
  • Is there any performance difference between the two? In G++ I can't find any significant difference in speed
  • Does the second code sample have any vulnerabilities (apart from the potential null pointer dereferencing that i checked for with the assertion)?

Greetings, TM3P

Was it helpful?

Solution

Does new do anything different than the void pointer casting does?

Yes; it constructs a new object, rather than attempting to assign to an object that doesn't actually exist.

Is there any performance difference between the two?

For trivial types, initialisation and assignment are effectively the same thing, so there will probably be little or no difference. For non-trivial types, they call different user-defined functions (constructor vs. assignment operator), which might do very different things.

Does the second code sample have any vulnerabilities?

For non-trivial types, the assignment operator might make assumptions about the state of the object before assignment, and might go horribly wrong, plunging the program into undefined behaviour, if there is no valid object.

tl;dr Placement new works, dodgy casting is bad.

OTHER TIPS

The first version uses placement new to copy-construct the object in the newly-allocated memory. This is the correct, well-defined way to turn raw byes into an object.

Your version treats the bytes as if they were already an object (via the cast) and then assigns a new value to that object, which gives undefined behaviour. If T is a very simple type this can be OK, but won't be any faster than the first version. If the type has an assignment operator then it will go very badly wrong.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top