c++ - operator+ 的规范实现涉及额外的移动构造函数

标签 c++ operator-overloading language-lawyer pass-by-reference pass-by-value

动机 this question ,我比较了一个二进制实现的两个不同版本 operator+operator+= 方面.考虑到我们在类 X 的定义中.

版本 1

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

版本 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);
}

在这两种情况下,operator+=定义如下:
X& operator+=(const X& rhs)    
{                             
  ... // whatever to add contents of X
  return *this;   
}

现在,我只运行以下代码并跟踪复制/移动构造函数的调用:
X a, b, c;
X d = a + b + c;

第一个“规范”版本有 1 个拷贝 + 2动构造函数调用,而第二个版本只有 1 个拷贝 + 1 动 构造函数调用(使用 GCC 10 和 -O3 测试)。

问题:在第一种情况下,是什么阻碍了额外的移动构造函数调用的省略?

现场演示:https://godbolt.org/z/GWEnHJ

附加观察:在实时演示中,类有一些内容(整数成员变量),移动构造函数调用没有/分别与第一个/第二个版本内联。此外,对于第二个版本,最终结果 6 在编译时计算并硬编码到程序集中(当传递给 operator<< 时),而对于第一个版本,它是从内存中读取的。通常,第二个版本似乎(相对)效率更高。但这很可能是由那些cout引起的。涉及的消息。没有它们,装配输出完全相同。

最佳答案

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


缺陷报告DR1148这被接受并包含在 C++11 中。
简而言之,它说(强调我的):

It is unclear whether copy elision is permitted when returning a parameter of class type. If not, it should still be possible to move, rather than copy, the return value.

Suggested resolution: Amend paragraph 34 to explicitly exclude function parameters from copy elision. Amend paragraph 35 to include function parameters as eligible for move-construction.


结果可以在
[class.copy.elision]/1.1 (强调我的)

in a return statement in a function with a class return type, when the expression is the name of a non-volatile object with automatic storage duration (other than a function parameter or a variable introduced by the exception-declaration of a handler ([except.handle])) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the object directly into the function call's return object

关于c++ - operator+ 的规范实现涉及额外的移动构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62179683/

相关文章:

c++ - 在 C++ 中覆盖 Cast 运算符

c++ - 使用模板类时没有合适的默认构造函数可用

C++ - Qt Creator 中的 Poco 库

python - 在 Python 中覆盖 'not' 运算符

c++ - 了解指向类型类成员的指针 - 无多态性

c++ - 避免在 C++ 中创建新的不可变实例的样板

c++ - 覆盖 C++ 中的运算符重载?

c++ - 动态上下文相关运算符的设计模式(例如模运算)?

c++ - 分配器命名要求——异常(exception)

c++ - 在 C 中递增一个 volatile 变量