Why does copy elision make an exception for formal parameters?

Here is the complete program:

#include <iostream> using std::cout; using std::endl; using std::move; int count {0}; // global for monitoring class Triple { public: Triple() = default; // C++11 use default constructor despite other constructors being declared Triple(Triple&&) = default; Triple(const Triple& t) : // copy constructor Triple(t.mX, t.mY, t.mZ) { count++; } Triple(const int x, const int y, const int z) : mX{ x }, mY{ y }, mZ{ z } { } const Triple& operator +=(const Triple& rhs) { mX += rhs.mX; mY += rhs.mY; mZ += rhs.mZ; return *this; } int x() const; int y() const; int z() const; private: int mX{ 0 }; // c++11 member initialization int mY{ 0 }; int mZ{ 0 }; }; #if 0 inline Triple operator+(const Triple& lhs, const Triple& rhs) { Triple left { lhs }; left += rhs; return left; } #else inline Triple operator+(Triple left, const Triple& rhs) { left += rhs; return left; } #endif int main() { Triple a,b; cout << "initial value of count is: " << count << endl; auto result { a+b }; cout << "final value of count is: " << count << endl; } 

An interesting fact is that the copy constructor has a side effect, and there are two versions of operator+ .

Case 1

 inline Triple operator+(const Triple& lhs, const Triple& rhs) { Triple left { lhs }; left += rhs; return left; } 

Case 2

 inline Triple operator+(Triple left, const Triple& rhs) { left += rhs; return left; } 

Visual Studio 2015 gives the same print result, result 1 . However, gcc 4.8.4 gives 2 for case 1.

This summary of issuing answers โ€ป says that "this is not a function parameter", which makes me assume that VS is wrong. It is right?

But why are formal parameter names handled specifically in this rule? Why is this not like any other local variable?

(I'm not saying that the optimizer will parse things depending on the calling conventions and in the light of a separate compilation of the caller and call-ee, but simply why this is not allowed.)

Edit: If you correctly print 1 , how does this compare with the elite rule?


Note โ€ป: I found that this text was copied from ยง12.8 of paragraph 31 in the public N3690 .

+1
c ++ copy-elision visual-c ++
source share
2 answers

First of all, understand that RVO and NRVO are features offered by standard writers to compiler authors. This compiler can ignore the possibility of RVO or NRVO if it cannot make it work, if it does not know if it can make it work if the moon is full, etc.

In this case, however, it is easy. The (N) RVO method is fundamentally implemented, it consists in constructing the return value directly in the memory occupied by the return value, or even in the memory occupied by the variable that will be set to this return value.

That is, the potential savings from (N) RVO arise not only from the ability to overcome the copy design, but also to the possibility of reducing copying in general.

But when the function parameter is the source of the return value, it is too late for that. left already somewhere in memory, and the return value should go somewhere else. Except for any brute force, somehow due to inlay, copying is already set because the second object is already built.

+1
source share

If the copy exception is disabled, both cases consist of 1 copy followed by 3 moves. (Any output 2 for your code indicates a compiler error).

Copy:

  • initialization left

and moves:

  • initialization of the return value from left
  • initialization of a temporary object indicated by a+b from the return value
  • initializing result from a+b

It would be more interesting to replace count with an output message with the message "in copy constructor" and "in move constructor" . You currently do not track moves at all.

If you follow the link, all 3 moves can be canceled. In the case of a buy-in value of 2 movements can be canceled. A move that cannot be undone is a transition from left to the return value.

I do not know the reasons why this step cannot be eliminated. It may be difficult for the compiler to do something like A a = foo( A() ); if A() could be overcome to a .

+1
source share

All Articles