Reputation: 1039
I wanted to compile for myself openttd sources. It was using Squirell library which i could not compile because of linker error. I looked up into the code which could not be compiled and i saw weird construct which I ( and linker :D ) could not understand :
new ((void *)&_vals[i]) T(v._vals[i]);
I modified the code so it looks now like that :
_vals[i] = *(new T(v._vals[i]));
I do not know wheter i modified the code in good way or not. I hope that i did it. Game is not crashing right now so maybe there is a chance that it works well.
Could someone please say why this construct is not doing any compile time errors, just linker errors? What exactly is this code doing?
Important information : I'm using visual studio 2013.
Upvotes: 0
Views: 159
Reputation: 9090
It is placement new:
new (addr) T(...)
Constructs the T
object at memory address addr
. Here it constructs it at the address &_vals[i]
, that is, it overwrites the object _vals[i]
. The address gets casted to void*
, i.e. a raw memory address.
This is sometimes used to re-construct an object, when it is immutable, or has no assignment operator implemented. For example
A a(1);
...
a.~A(); // needed as otherwise a would not get destructed
new (&a) A(2);
...
Makes a new A
object at the same address than the old one, keeping references and pointers to it valid.
It is a low-level operation and can cause problems, i.e. with memory alignment when it is not sure that addr
is suitable for the object.
The modified code instead constructs a new object on the heap, and assigns it to the existing object, and leaks it. This would not leak memory in that case:
_vals[i] = T(v._vals[i]);
The linker error is probably because there is no T::operator=(const T&)
, and because of that placement new was used. (For example if T contains a reference member and is immutable)
Upvotes: 1
Reputation: 76848
Your modification has introduced a memory leak. Before, the new object was constructed into already allocated memory using placement new. Now you create an object using new
and then copy that into _vals
. However, you never call delete
on the original.
Upvotes: 3
Reputation: 157414
It's standard placement new. You're probably missing
#include <new>
Upvotes: 4