为什么 C++ 中重载二元算术运算符的规范实现按值通过了第一次争论?

Why does cannonical implementation of overloading binary arithmatic operator in C++ pass first arguement by value?

根据 this cppreference page,按值传递重载二元运算符的第一个参数以某种方式优化了表达式,如 a + b + c。链接页面的相关代码片段如下:

class X
{
 public:
  X& operator+=(const X& rhs)         // compound assignment (does not need to be a member,
  {                                   // but often is, to modify the private members)
    /* addition of rhs to *this takes place here */
    return *this;                     // return the result by reference
  }

  // friends defined inside class body are inline and are hidden from non-ADL lookup
  friend X operator+(X lhs,           // passing lhs by value helps optimize chained a+b+c
                     const X& rhs)    // otherwise, both parameters may be const references
  {
    lhs += rhs;                       // reuse compound assignment
    return lhs;                       // return the result by value (uses move constructor)
  }
};

关于这个我有 2 个问题:

  1. 链式 a + b + c 表达式如何由此优化?
  2. 假设 X 也覆盖了复制和移动赋值运算符和构造函数,像 x = a + b 这样的语句会产生任何复制吗?为什么或为什么不?

我不知道这是否考虑了示例作者,但有一些解释。考虑一下这段代码中会发生什么:

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

这里,首先,a + b基本被计算为operator+(operator+(a, b), c)。请注意,operator+(a, b) 是一个 rvalue,因此,lhs 可以在 operator+ 的外部应用程序中由 初始化移动构造函数

根据 operator+= 实现 operator+ 的另一种方法如下:

friend X operator+(const X& lhs, const X& rhs) 
{    
   X temp(lhs);
   temp += rhs;
   return temp;
}

请注意,您需要创建一个临时对象,因为您需要一个对象来应用 operator+=。使用此解决方案,operator+operator+(operator+(a, b), c) 中的两个应用程序都涉及 copy-constructor.

现场演示:https://godbolt.org/z/5Dq7jF

当然,你可以为rvalues添加第二个版本,如下:

friend X operator+(X&& lhs, const X& rhs) 
{    
   lhs += rhs;
   return std::move(lhs);
}

但这比原来的值传递版本需要更多的输入。


一般情况下,值传递常用于需要统一左值和右值重载的情况;例如,查找 统一赋值运算符.