【问题标题】:C++ - why implement op+ in terms of op+= and not the other way around?C++ - 为什么用 op+= 来实现 op+ 而不是相反?
【发布时间】:2016-11-29 11:09:17
【问题描述】:

为什么会这样实现:

T& T::operator+=( const T& ) {
  // ... implementation ...
  return *this;
}

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

比这个传播得更频繁:

T& T::operator+=( const T& rhs ) {
  *this = *this + rhs;
  return *this;
}

T operator+( const T& lhs, const T& rhs ) {
  // ... implementation ...
  return some_result;
}

是否有任何原因,或者只是一个偶然的巧合,我看到人们在我阅读的文献中多次以这种方式实现它,而从来没有相反的方式?

【问题讨论】:

  • 测试第二个,你会发现它不起作用。究竟它如何不起作用将取决于// ... implementation ... 中发生的事情,但它不会起作用。最有可能的是,return *this + rhs; 将完全无法对 this 做任何事情。
  • @user2357112:我的回答是否解释了您发现的问题,还是有其他问题?
  • 请不要通过查看答案来更改帖子。它会使答案毫无用处
  • @user2357112 下面的答案是。晚了;我没有想清楚。很抱歉这个错误。
  • @BenVoigt:是的,你的回答似乎解决了所有问题。

标签: c++ operator-overloading code-reuse


【解决方案1】:

operator+ 必须创建一个新对象来保存结果。 operator+= 不需要新对象。

如果您将operator+= 写成operator+,那么您最终会为额外的新对象创建、分配(或交换)和销毁付出代价,而所有这些都是您不需要的。

除此之外,在许多处理器上,硬件直接支持+= 和类似操作,其中结果被存储回输入寄存器之一,而没有用于存储到第三个寄存器(如+)。

顺便说一句,您的(原始,现已编辑)代码中有一个错误,隐藏了部分额外工作。你实际上需要:

T& T::operator+=( const T& rhs )
{
    *this = *this + rhs; // creation of temporary, move assignment, and destruction of temporary
    return *this;
}

更糟糕的是,您(同样是原始的,现在已编辑)建议的 operator+ 实现无法正确返回新对象,而是返回一个悬空引用。这是未定义的行为。


对于那些感兴趣的人,第一个 operator+ 实现可以通过使用传递值进一步改进:

T operator+( T lhs, const T& rhs )
{
    lhs += rhs;
    return lhs;
}

现在如果operator+ 的左侧操作数是临时的,将使用移动构造函数,避免复制。尽管使用 NRVO,但无论哪种方式,生成的代码都可能没有太大优势。

【讨论】:

  • 但是我们不还是创建一个新对象吗?我们在一种情况下创建 T temp,在另一种情况下创建 some_result。这不归结为同一件事吗?
  • @EnnMichael:operator+= 的直接实现中没有任何内容可以创建新对象。考虑std::complex<T>,它看起来像T& std::complex<T>::operator+=(const std::complex<S>& rhs) { re += rhs.re; im += rhs.im; return *this; } 没有创建新的临时对象,每个语句都精确映射到单个CPU 指令(在常见架构上)
  • @EnnMichael:如果您要问operator+(不是+=)的两种变体是否都创建了一个临时对象,是的,这是必要的。这也是我的回答开始说的。您建议的方法的问题非常低效+=
  • 非常感谢!我现在明白了。在我的版本中,高效的 operator+ 保持不变,只是我的 operator+= 更糟,因为它执行了额外的复制操作。
  • @Yakk 参数首先不应该符合条件。
猜你喜欢
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
  • 2012-03-29
  • 1970-01-01
  • 1970-01-01
  • 2017-02-21
  • 1970-01-01
相关资源
最近更新 更多