I have some code that returns a class object by value and the copy constructor is being called more than I thought it would. This seems to be how the g compiler does things but I'm not sure why. Say I have this code:
#include <memory>
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "constructor" << endl; }
A(const A& other) { cout << "copy constructor" << endl; }
~A() { cout << "destructor" << endl; }
};
A f()
{
return A();
}
int main()
{
cout << "before f()\n";
A a = f();
cout << "after f()\n";
return 0;
}
When compiled with constructor elision turned off
g test.cpp -fno-elide-constructors
it outputs this:
before f()
constructor
copy constructor
destructor
copy constructor
destructor
after f()
destructor
So the copy constructor is called twice. I can see why the copy constructor would be called when copying the return value of f()
into the variable a
but why again?
I've read about C compilers returning temporary objects from functions but I don't understand the point of that. Even with elision turned off it seems unnecessary to create a temporary object for every function return value.
Update
Just to be super clear here, I'm not surprised that the copy constructor is being called. I expect that since I turned off elision. What I'm confused about is why the copy constructor needs to be called twice. It seems like once should be enough to copy the result from f()
into a
.
CodePudding user response:
In Pre-C 17 standard there was non-mandatory copy elison, so by using the -fno-elide-constructors
flag you are disabling the return value optimization and some other optimizations where copies are elided.
This is what is happening in your program:
- First due to the return statement
return A();
an object is constructed using the default constructorA::A()
. - Next, a copy of that default constructed object is returned to the caller. This is done using the copy constructor
A::A(const A&)
. Hence you get the first copy constructor call output. - Finally, the object named
a
is created as a copy of that returned value using the copy constructorA::A(const A&)
. Hence you get the second copy constructor call output.
In C 17, due to mandatory copy elison, you will not get any copy constructor call output. Demo.
CodePudding user response:
It's because pre C 17, compilers were not mandated to elide the copies. If you do turn on compiling this as C 17 or later, there will only be one constructor call - even if you use -fno-elide-constructors
.