I have a following code:
#include <iostream>
using namespace std;
struct A
{
A() {}
A(const A&) { cout << "copy const" << endl; }
A(A&) { cout << "copy non const" << endl; }
};
A f(A a)
{
return a;
}
int main() {
A a1 = f(A());
}
The A(A&)
copy constructor is called. Why A(const A&)
is not called since I pass a temporary object?
When I comment out the A(const A&)
copy constructor the program does not compile.
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
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