#include <iostream>
using namespace std;
class A
{
int x;
public:
A(int c) : x(c) {}
A(const A& a) { x = a.x; cout << "copy constructor called" << endl;}
};
class B
{
A a;
public:
B(int c) : a(c) {}
B(const B& b) : a(b.a) { }
A get_A() { return a;}
};
int main()
{
B b(10);
A a1 = b.get_A();
}
In the code above, I expected that 'copy constructor called' message would pop up twice because first, the b.get_A() will create a temporary object which invokes copy constructor (1) and second, it will copy its reference to a1 's copy constructor (2) , thus making two messages showing up.
However, the code actually results a single 'copy constructor called' message. Why?
The C++ standard allows for the copy constructor to be elided in certain situations. Typically, this means if an object will be copy constructed from a temporary variable. It can be constructed in place.
In this case get_A();
has returned a copy, into a temporary. You then assign a1
to that temporary variable. The compiler is allowed to elide the extra copy and construct a1
in place with the return value of get_A()
.
This optimization can occur, even when the copy constructor has side effects.
Copy elision is the only allowed form of optimization that can change the observable side-effects. Because some compilers do not perform copy elision in every situation where it is allowed, programs that rely on the side-effects of copy/move constructors and destructors are not portable.
In C++11 the code might invoke a move constructor to move the object rather than copy it or in both C++03 and C++11 compiler optimizations in the form of NRVO might apply copy elision to elide the copy.
Note that latter(copy elision) depends on capability of the compiler and is not guaranteed while former(Move semantics) is guaranteed in C++11.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With