动机 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/