Temporary objects

What is a temporary object?

A temporary object is an instance (object) of a class that is created, without a name, and is destructed immediately after its creation. It is created by calling the constructor a class as if is was a function.

When a constructor is called that way, it returns is a temporary object.

Let us look at the code below:

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
#include <iostream> class A { public: A(const std::string & name) : _name(name) { std::cout << "Object \"" << _name << "\" created!" << std::endl; } ~A() { std::cout << "Object \"" << _name << "\" destructed!" << std::endl; } private: std::string _name; }; int main() { std::cout << "Before." << std::endl; A("Temporary object"); std::cout << "After." << std::endl; return 0; }

In the code above, a temporary object of type A is created, returned and then deleted. However, here, nothing is done with it, so the only result is that its constructor and destructor are called.

Assigning a temporary object to an object

By default, when we assign an object to an other object of the same type, using the assignment operator =, the result is that the value of each member of the right operand is copied to the left operand.

Now, let us replace the main from the code above by the following:

1
2
3
4
5
6
7
int main() { A obj1("Obj1"); A obj2 = A("Obj2"); return 0; }

Are both the object definitions from above equivalent? The answer is: In theory, no, but in practice, yes.

In theory, what happens at the definition of obj2 is that a temporary object of type A is created and returned. The object obj2, instead of being created using its constructor, is created by assigning its members with the values of the members of the temporary object. The temporary object is then deleted. However, in practice, the definition of obj2 is optimized so its constructor is called with the argument "Obj2" instead.

At compilation time, the following line:

A obj2 = A("Obj2");

Becomes:

A obj2("Obj2");

Functions returning objects

Functions returning objects (Not references nor pointers) return copies of the objects as a temporary objects.

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
#include <iostream> class A { public: A(const std::string & name) : _name(name) { std::cout << "Object \"" << _name << "\" created!" << std::endl; } ~A() { std::cout << "Object \"" << _name << "\" destructed!" << std::endl; } private: std::string _name; }; A func(const std::string & name) { A a(name); return a; } int main() { A b = func("Obj"); return 0; }

Again, in the example above, what happens in theory and in practice is different. What happens in theory is: The object a, inside the function func, is created using its constructor. The function func returns a temporary object that is a copy of the object a (Constructed by copy instead of by calling the constructor defined in the example above). Then, the end of the function is reached so a is destroyed. The object b is created by copying the members of the temporary object returned by the function func. Since the returned object is a temporary object, it is then destroyed. The object b is destroyed at the end of the main function. So, in theory, there is 1 object created using the constructor which header is A(const std::string & name), 2 objects created by copy and 3 objects destructed.

However, in practice, since there are, in the steps presented above, many unnecessary object creations, they are taken off (optimized out) by the compiler so there is only 1 object creation. Basically, the intermediates are skipped and the object is directly constructed using the constructor of the object b.

The line A b = func("Obj"); is then, in practice, equivalent to A b("Obj");.

Even if we do not 'catch' the temporary object returned, there is still an object created:

1
2
3
4
5
6
int main() { func("Obj"); return 0; }