operator+ 的规范实现涉及额外的移动构造函数
Canonical implementation of operator+ involves additional move constructor
受 的启发,我根据 operator+=
比较了二进制 operator+
的两个不同版本的实现。考虑我们在 class 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;
}
现在,我只是 运行 以下代码并跟踪了 copy/move 构造函数的调用:
X a, b, c;
X d = a + b + c;
对于第一个 "canonical" 版本,有 1 次复制 + 2 次 move 构造函数调用,而对于第二个版本只有 1 个副本 + 1 个 move 构造函数调用(使用 GCC 10 和 -O3
测试)。
问题:在第一种情况下,是什么阻碍了对附加移动构造函数调用的省略?
现场演示:https://godbolt.org/z/GWEnHJ
补充观察:在现场演示中,class有一些内容(整数成员变量),移动构造函数调用是not/are与first/second版本内联,分别。此外,对于第二个版本,最终结果 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
受 operator+=
比较了二进制 operator+
的两个不同版本的实现。考虑我们在 class 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;
}
现在,我只是 运行 以下代码并跟踪了 copy/move 构造函数的调用:
X a, b, c;
X d = a + b + c;
对于第一个 "canonical" 版本,有 1 次复制 + 2 次 move 构造函数调用,而对于第二个版本只有 1 个副本 + 1 个 move 构造函数调用(使用 GCC 10 和 -O3
测试)。
问题:在第一种情况下,是什么阻碍了对附加移动构造函数调用的省略?
现场演示:https://godbolt.org/z/GWEnHJ
补充观察:在现场演示中,class有一些内容(整数成员变量),移动构造函数调用是not/are与first/second版本内联,分别。此外,对于第二个版本,最终结果 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