Reputation: 8043
The following code prints only A::A()
, but no A::A(const A&)
or operator=
. Why?
struct A
{
A() { cout << "A::A()" << endl; }
A(const A& value) { cout << "A::A(const A&)" << endl; }
A& operator=(const A& newValut)
{
cout << "A::operator=" << endl;
return *this;
}
};
A foo()
{
A a; //Ok, there we have to create local object by calling A::A().
return a; //And there we need to copy it, otherwise it will be destroyed
//because it's local object. But we don't.
}
int main()
{
A aa = foo(); //Also there we need to put result to the aa
//by calling A::A(const A&), but we don't.
}
So this code must print
A::A()
A::A(const A&)
A::A(const A&)
But it doesn't. Why?
I suggest that there is no inlining of foo()
under g++
without optimizations.
Upvotes: 0
Views: 147
Reputation: 651
In Visual Studio 2022 version 17.4 and later, you can explicitly enable optional copy or move elision behavior by using the /Zc:nrvo compiler option.
https://learn.microsoft.com/en-us/cpp/build/reference/zc-nrvo?view=msvc-170
Upvotes: 0
Reputation: 721
This is how returning of a complex type is done in C++: the location for the returned object is actually provided by the caller before the call to the function and a pointer to this not yet initialized object is passed as an hidden argument to the function. The function use this memory location to construct the returned object from the returned expression.
So when the returned object is to directly initialized a new object like in your program A aa = foo();
, it does not need to copy the returned value to the object on the stack. It asks the function to create the object directly at this location. So only one call at most to the copy constructor is to be done. (In fact, if you had 2 calls to the copy constructor, the C++ compiler would not be compliant).
Now, on top of that, the compiler is allowed to optimize away this call in an optimization called "Return Value Optimization" or RVO. How is that possible? If you look at your code, you can see that you can directly define the local "a" variable in foo() at the proposed location of the returned value, and so do not have to copy it again. This is an important feature because copy constructor can be complex and slow to run, so this can improve performance significantly when implemented (and every compiler I know do implement this feature).
So in your case, depending on the compiler, you may have 1 or 0 call to the copy constructor and your compiler is still compliant.
Upvotes: 3
Reputation: 1334
This is called "Return Value Optimization". The compiler is allowed to elide the copy in a case like this.
Upvotes: 10