5
#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?

Jaebum
  • 1,397
  • 1
  • 13
  • 33
  • possible duplicate of [Why copy constructor is not called in this case?](http://stackoverflow.com/questions/1758142/why-copy-constructor-is-not-called-in-this-case) – JoeG May 26 '13 at 07:30

2 Answers2

9

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.

Steve
  • 7,171
  • 2
  • 30
  • 52
3

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.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • I used visual studio 2012 (which supports c++11) and move constructor did not invoked :( – Jaebum May 26 '13 at 07:31
  • A(const A&& a) { x = a.x; cout << "move called" < – Jaebum May 26 '13 at 07:31
  • 1
    @LeeJaeBeom: Typically, all good compilers will apply copy elision optimization but note that the compiler doesn't have to apply this optimization. It is not guaranteed. On gcc you can use the `-fno-elide-constructors` setting to check the behavior by exlicitly disabling copy elision. – Alok Save May 26 '13 at 07:33
  • @AlokSave; thanks, i can see temporary `constructors` and `destructors` now. – Fredrick Gauss Oct 20 '13 at 22:08