Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 运算符+的规范实现;包含额外的移动构造函数_C++_Operator Overloading_Language Lawyer_Pass By Reference_Pass By Value - Fatal编程技术网

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,但这个解决方案完全绕过
操作符+
for
X
。相反,它将
X
对象转换为
int
,在那里添加,然后转换回
X
。简单演示:将
int
-转换构造函数和
int
-cast运算符
显式化
。然后,代码将不会编译。@Taekahn此外,尽管您的解决方案是相关的,但我的问题不是如何避免构造函数调用。我问了为什么在所描述的情况下不会发生省略。“规范的”之所以称为版本,是因为它简单而安全,不一定是最优的。复制和交换赋值运算符有类似的情况,即复制和交换简单而安全,但不如像您这样为值类别定义不同的重载done@TedLyngmo谢谢,我现在很忙,但过几天会检查你的答案。