Operator +的规范实现涉及其他move构造函数 [英] Canonical implementation of operator+ involves additional move constructor

查看:60
本文介绍了Operator +的规范实现涉及其他move构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出于此问题的动机,我比较了二进制 operator + 以 operator + = 表示.考虑我们在类 X 的定义内.

Motivated by this question, I compared two different versions of an implementation of a binary operator+ in terms of operator+=. Consider we are inside the definition of class 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 + = 的定义如下:

Where, in both cases, operator+= is defined as follows:

X& operator+=(const X& rhs)    
{                             
  ... // whatever to add contents of X
  return *this;   
}

现在,我只运行以下代码并跟踪复制/移动构造函数的调用:

Now, I just run the following code and tracked calls of copy/move constructors:

X a, b, c;
X d = a + b + c;

在第一个规范" 版本中,有1个副本+ 2个移动构造函数调用,而在第二个版本中,只有1个副本+ 1个移动构造函数调用(已在GCC 10和 -O3 上进行了测试).

With the first "canonical" version, there were 1 copy + 2 move constructor calls, while with the second version there were just 1 copy + 1 move constructor calls (tested with GCC 10 and -O3).

问题:在第一种情况下是什么原因阻碍了额外的move构造函数调用?

实时演示: https://godbolt.org/z/GWEnHJ

其他观察结果:在实时演示中,该类具有一些内容(整数成员变量),移动构造函数调用不在/em 内联第一个/第二个版本,分别是 .同样,对于第二个版本,最终结果6是在编译时计算并硬编码到程序集中的(当传递给 operator<< 时),而对于第一个版本,则从记忆.通常,第二个版本似乎(相对)效率更高.但这可能是由所涉及的 cout 消息引起的.没有它们,程序集的输出将完全相同.

Additional observation: In the live demo, where the class has some contents (integer member variable), the move constructor calls are not/are inlined with the first/second version, respectively. Also, with the second version, the final result 6 is calculated at compile time and hard-coded into the assembly (when passed to operator<<), while with the first version, it is read from memory. Generally, the second version seems to be (relatively) much more efficient. But this was likely caused by those cout messages involved. Without them, the assembly output was exactly the same.

推荐答案

在第一种情况下,是什么阻碍了额外的move构造函数调用的选择?

What hinders the elision of that additional move constructor call in the first case?

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

The defect report DR1148 that was accepted and included in C++11.

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

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

It is unclear whether copy elision is permitted when returning a parameter of class type. If not, it should still be possible to move, rather than copy, the return value.

建议的分辨率:修改第34段,以便从复制省略中明确排除功能参数.修改第35段,使其包含适合进行移动构造的功能参数.

Suggested resolution: Amend paragraph 34 to explicitly exclude function parameters from copy elision. Amend paragraph 35 to include function parameters as eligible for move-construction.

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

expression 是具有自动存储持续时间的非易失性对象的名称时,

在具有类返回类型的函数中的 return 语句中

除了功能参数或由处理程序异常声明引入的变量( [except.handle] ))与函数返回类型具有相同的类型(忽略cv限定),可以通过将对象直接构造到函数调用的返回对象中来省略复制/移动操作

in a return statement in a function with a class return type, when the expression is the name of a non-volatile object with automatic storage duration (other than a function parameter or a variable introduced by the exception-declaration of a handler ([except.handle])) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the object directly into the function call's return object

这篇关于Operator +的规范实现涉及其他move构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆