C++ 运算符+的规范实现;包含额外的移动构造函数
受此启发,我比较了二进制C++ 运算符+的规范实现;包含额外的移动构造函数,c++,operator-overloading,language-lawyer,pass-by-reference,pass-by-value,C++,Operator Overloading,Language Lawyer,Pass By Reference,Pass By Value,受此启发,我比较了二进制运算符+实现的两个不同版本,即运算符+=。考虑到我们在类 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;
运算符+
实现的两个不同版本,即运算符+=
。考虑到我们在类<代码> 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);
}
其中,在这两种情况下,运算符+=
的定义如下:
X& operator+=(const X& rhs)
{
... // whatever to add contents of X
return *this;
}
现在,我只运行以下代码并跟踪复制/移动构造函数的调用:
X a, b, c;
X d = a + b + c;
在第一个“规范”版本中,有1个copy+2个move构造函数调用,而在第二个版本中,只有1个copy+1个move构造函数调用(使用GCC 10和-O3
进行测试)
问题:在第一种情况下,是什么阻碍了省略额外的move构造函数调用?
现场演示:
附加观察:在实时演示中,类有一些内容(整型成员变量),移动构造函数调用没有/分别与第一个/第二个版本内联。另外,对于第二个版本,最终结果6在编译时计算,并硬编码到程序集中(当传递给
操作符时)
在第一种情况下,是什么阻碍了省略额外的move构造函数调用
已接受并包含在C++11中的缺陷报告
简而言之,它说(强调我的):
不清楚在返回类类型的参数时是否允许复制省略。如果不允许,则仍然可以移动而不是复制返回值
建议的解决方案:修改第34段,明确将功能参数排除在复制省略中。修改第35段,将功能参数纳入移动构造
结果见
(强调矿山)
在具有类返回类型的函数中的return
语句中,当表达式是具有自动存储持续时间的非易失性对象的名称(而不是具有相同类型的函数参数或处理程序的异常声明([except.handle]
)引入的变量时(忽略cv限定)作为函数返回类型,可以通过将对象直接构造到函数调用的返回对象中来省略复制/移动操作
根据我之前的评论,这确实为我删除了所有的移动。对我来说,这表明我的答案是发生了什么…@Taekahn,但这个解决方案完全绕过操作符+
forX
。相反,它将X
对象转换为int
,在那里添加,然后转换回X
。简单演示:将int
-转换构造函数和int
-cast运算符显式化
。然后,代码将不会编译。@Taekahn此外,尽管您的解决方案是相关的,但我的问题不是如何避免构造函数调用。我问了为什么在所描述的情况下不会发生省略。“规范的”之所以称为版本,是因为它简单而安全,不一定是最优的。复制和交换赋值运算符有类似的情况,即复制和交换简单而安全,但不如像您这样为值类别定义不同的重载done@TedLyngmo谢谢,我现在很忙,但过几天会检查你的答案。