运算符+ 的规范实现涉及额外的移动构造函数

Canonical implementation of operator+ involves additional move constructor

本文关键字:移动 构造函数 实现 范实现 运算符      更新时间:2023-10-16

受这个问题的启发,我比较了二进制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消息引起的。没有它们,程序集输出完全相同。

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

缺陷报告 DR1148 被接受并包含在 C++11 中。

简而言之,它说(强调我的(:

目前尚不清楚在返回类类型的参数时是否允许复制省略。如果没有,应该仍然可以移动而不是复制返回值。

建议的解决方案:修改第34段,明确排除函数参数。修正第35段,列入符合移动结构条件的功能参数。

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

在具有类返回类型的函数的return语句中,当表达式是具有自动存储持续时间的非易失性对象的名称(函数参数处理程序异常声明引入的变量除外(时([except.handle](具有与函数返回类型相同类型(忽略 cv-quality(的类型,可以通过将对象直接构造到函数调用中来省略复制/移动操作。返回对象