Dan*_*ica 5 c++ operator-overloading pass-by-reference pass-by-value language-lawyer
通过启发这个问题,我比较了两个不同版本的二进制的实施operator+来讲operator+=。考虑我们在 class 的定义中X。
版本 1
friend X operator+(X lhs, const X& rhs)
{
lhs += rhs;
return lhs;
}
Run Code Online (Sandbox Code Playgroud)
版本 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);
}
Run Code Online (Sandbox Code Playgroud)
其中,在这两种情况下,operator+=定义如下:
X& operator+=(const X& rhs)
{
... // whatever to add contents of X
return *this;
}
Run Code Online (Sandbox Code Playgroud)
现在,我只运行以下代码并跟踪复制/移动构造函数的调用:
X a, b, c;
X d = a + b + c;
Run Code Online (Sandbox Code Playgroud)
在第一个“规范”版本中,有 1 个副本 + 2 个移动构造函数调用,而在第二个版本中,只有 1 个副本 + 1 个移动构造函数调用(使用 GCC 10 和 测试-O3)。
问题:在第一种情况下是什么阻碍了额外的移动构造函数调用的省略?
现场演示:https : //godbolt.org/z/GWEnHJ
附加观察:在现场演示,其中所述类有一些内容(整数成员变量)时,移动电话的构造并不/被内联与所述第一/第二版,分别。此外,对于第二个版本,最终结果 6 在编译时计算并硬编码到程序集中(当传递给 时operator<<),而对于第一个版本,它是从内存中读取的。通常,第二个版本似乎(相对)效率更高。但这很可能是由这些cout消息引起的。没有它们,装配输出完全相同。
在第一种情况下,是什么阻碍了额外的移动构造函数调用的省略?
缺陷报告DR1148已被接受并包含在 C++11 中。
简而言之,它说(强调我的):
目前尚不清楚返回类类型的参数时是否允许复制省略。如果没有,应该仍然可以移动而不是复制返回值。
建议的解决方案:修改第 34 段以明确从复制省略中排除函数参数。修改第 35 段,将函数参数纳入移动构造的资格。
结果可以在 [class.copy.elision]/1.1中找到(重点是我的)
在
return具有类返回类型的函数的语句中,当表达式是具有自动存储持续时间的非易失性对象的名称(函数参数或由处理程序的异常声明引入的变量( )除外)时,与函数返回类型相同的类型(忽略 cv 限定),可以通过将对象直接构造到函数调用的返回对象中来省略复制/移动操作[except.handle]