动机是 这个问题我比较了二进制的两个不同版本的实现。operator+
就...而言 operator+=
. 考虑我们在类的定义里面 X
.
第一版
friend X operator+(X lhs, const X& rhs)
{
lhs += rhs;
return lhs;
}
第二版
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;
}
现在,我只是运行下面的代码,并跟踪copymove构造函数的调用。
X a, b, c;
X d = a + b + c;
第一个 "规范" 版本,有1个副本+ 2动 构造函数的调用,而第二个版本只有1个拷贝+的 1招 构造函数调用(用GCC 10和 -O3
).
问题是:在第一种情况下,是什么阻碍了那个额外的移动构造函数调用的洗脱?在第一种情况下,是什么阻碍了额外的移动构造函数调用的省略?
现场演示。https:/godbolt.orgzGWEnHJ。
补充意见: 在现场演示中,当类中有一些内容(整数成员变量)时,移动构造函数会调用 不属于 衬托 前二分之一 版本。分别. 另外,在第二个版本中,最终结果6在编译时计算,并硬编码到汇编中(当传递给 operator<<
),而第一个版本则是从内存中读取。一般来说,第二个版本似乎(相对)更有效率。 但这很可能是由那些 cout
所涉及的消息。如果没有它们,汇编的输出是完全一样的。
在第一种情况下,是什么阻碍了那个额外的移动构造函数调用的精简?
缺陷报告 DR1148 被接受并包含在C++11中。
简而言之,它说(强调我):
不清楚在返回类型参数时,是否允许复制删除。如果不允许,仍然可以移动而不是复制返回值。
建议的解决方案。修正第34段 明确地将函数参数排除在复制洗脱之外。. 修正第35段,将功能参数列为符合移动施工条件的参数。
结果见:[class.copy.elision]1.1。 (强调我)
在...中
return
类返回类型的函数中的语句,当 表情 是一个具有自动存储时间的非易失性对象的名称(非函数参数 或一个变量引入的 异常声明 的 处理者 ([except.handle]
)),类型与函数返回类型相同(忽略cv限定),可以直接将对象构造到函数调用的返回对象中,省略copymove操作