Shoter
Shoter

Reputation: 1039

Weird c++ construct

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

Whole source code(line 41)

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

Answers (3)

tmlen
tmlen

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

Björn Pollex
Björn Pollex

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

ecatmur
ecatmur

Reputation: 157414

It's standard placement new. You're probably missing

#include <new>

Upvotes: 4

Related Questions