Canonical implementation of operator+ involves additional move constructor

半腔热情 提交于 2020-06-11 06:09:08

问题


Motivated by this question, I compared two different versions of an implementation of a binary operator+ in terms of operator+=. Consider we are inside the definition of class X.

Version 1

friend X operator+(X lhs, const X& rhs)   
{
   lhs += rhs;  
   return lhs; 
}

Version 2

friend X operator+(const X& lhs, const X& rhs) 
{    
   X temp(lhs);
   temp += rhs;
   return temp;
}

friend X operator+(X&& lhs, const X& rhs) 
{    
   lhs += rhs;
   return std::move(lhs);
}

Where, in both cases, operator+= is defined as follows:

X& operator+=(const X& rhs)    
{                             
  ... // whatever to add contents of X
  return *this;   
}

Now, I just run the following code and tracked calls of copy/move constructors:

X a, b, c;
X d = a + b + c;

With the first "canonical" version, there were 1 copy + 2 move constructor calls, while with the second version there were just 1 copy + 1 move constructor calls (tested with GCC 10 and -O3).

Question: What hinders the elision of that additional move constructor call in the first case?

Live demo: https://godbolt.org/z/GWEnHJ


Additional observation: In the live demo, where the class has some contents (integer member variable), the move constructor calls are not/are inlined with the first/second version, respectively. Also, with the second version, the final result 6 is calculated at compile time and hard-coded into the assembly (when passed to operator<<), while with the first version, it is read from memory. Generally, the second version seems to be (relatively) much more efficient. But this was likely caused by those cout messages involved. Without them, the assembly output was exactly the same.

来源:https://stackoverflow.com/questions/62179683/canonical-implementation-of-operator-involves-additional-move-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!