The operator placement new

Location
  1. Courses

    /

  2. Complete C++ Course

    /

  3. Object oriented programming

    /

  4. The operator placement new

The operator placement new vs new

The operator new may receive a memory address as argument. Usually, the operator new dynamically allocates memory and then creates the object inside it. However, when it is given an argument, it constructs the object at the address received in argument and does not allocate memory. In that case, it is called the operator placement new.

Constructing objects inside already allocated memory

The operator placement new is used the same way as the operator new, except that we must put, after the keyword new and inside parentheses, the memory address to build the object at.

Here is an example where we construct an object inside a static array of bytes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream> class A { public: A(float a) : _a(a) {} void print() { std::cout << _a << std::endl; } private: float _a; }; int main() { char bytes[sizeof(A)]; // Creates an object of type 'A' inside the array 'bytes'. new(bytes) A(7.3); // Casts the array 'bytes' into a pointer of type 'A' and calls its method 'print'. ((A*)bytes)->print(); return 0; }

There is also the operator placement new[] used to construct many objects at once:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream> class A { public: A(const std::string & str) : _str(str) {} void print() { std::cout << _str << std::endl; } private: std::string _str; }; int main() { char bytes[3 * sizeof(A)]; // Creates 3 objects of type 'A' inside the array 'bytes'. new(bytes) A[3]{ {"First object."}, {"Second object."}, {"Third object."} }; A *ptr = (A*)bytes; ptr[0].print(); ptr[1].print(); ptr[2].print(); return 0; }

Note that both placement new operators return a pointer to the address the object has been constructed at.

Calling the destructor

When we define an object of a class, its destructor is automatically called when it reaches the end of its life span. When we allocate objects using the operators new and new[], the destructor of the objects is automatically called by the operators delete and delete[]. When we construct objects using the placement new and placement new[] operators, we do not have to use the operators delete and delete[] to free the memory, so their constructor is never called. If we want the destructors of objects constructed using the placement new operators, to be called, we have to call them manually, as if they were normal methods. Note that calling the destructor of an object is necessary only if its destructor does something or if it contains member objects that need to have their destructor called. Otherwise, it does nothing.

Here is an example where the destructor of an object constructed using the placement new operator is explicitly called:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream> class A { public: A(double a) : _a(a) { std::cout << "A(" << _a << ")\n"; } ~A() { std::cout << "~A()\n"; } private: double _a; }; int main() { char bytes[sizeof(A)]; // Constructs an object of the class A. new(bytes) A(1234.56); // Call its destructor. ((A*)bytes)->~A(); // Constructs an other object of the class A. new(bytes) A(78.9); // Call its destructor. ((A*)bytes)->~A(); return 0; }

An example with placement new[]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream> class A { public: A() { std::cout << "A()\n"; } ~A() { std::cout << "~A()\n"; } }; int main() { char bytes[3 * sizeof(A)]; // Constructs 3 objects of the class A. new(bytes) A[3]; A *ptr = (A*)bytes; // Calls the destructor of each object inside the array 'bytes'. ptr[0].~A(); ptr[1].~A(); ptr[2].~A(); return 0; }