What you are seeing is a mix of copy elision and an actual copy being made. Since f
takes a
by value, It needs to copy A()
into a
. The compiler sees this copy really isn't needed, so it elides that and instead directly constructs a
so you don't see any call. In the body of f
when you return a;
, it needs to copy a
into the return value. Since a
is a lvalue, A(A&)
is a better match than A(const A&)
so you see the call to the non const copy constructor. Then a1
needs to be initialized from f
's return value. Again copy elision comes into play again and instead of seeing a copy it just directly puts the return value into a1
's storage.
So, elide, non-const copy, elide, which leaves the output with just copy non const
You get an error when you remove A(const A&)
because even though those copies were elided, C++ still required there to be copy constructor until C++17.
If you compile with gcc or clang and use -fno-elide-constructors
you can actually see those copies. You can see that in this live example. Note that I used -std=c++11
to turn off C++17's guaranteed copy elision