对operator +和/或operator + =使用移动语义是否有意义?

时间:2012-03-24 11:00:20

标签: c++ c++11 operator-overloading move

我想知道在重载operator +和/或operator + =时使用移动语义是什么样的情况。尽管在this question中解释了如何做到这一点,但我无法理解为什么要这样做。我们考虑运算符+ =。如果我只是通过引用右侧传递并在左侧对象上进行适当的更改,则无论如何都没有不必要的副本。所以我们回到同一点:在这种情况下移动语义是否有益?

2 个答案:

答案 0 :(得分:12)

是和否。

<强>运算符+ =

移动语义通常不一定对operator+=有用,因为您已经在修改左侧参数(this),因此您已经拥有了大部分时间都可以使用的资源。 / p>

尽管如此,作为优化,它可能是值得的。想象一个std::string实现,其默认构造函数不分配任何内存。然后std::string::operator+=(std::string&&)可以简单地从RHS窃取资源。或者想象一下,RHS缓冲区大到足以保存所有内容,但LHS不是,那么如果你可以使用RHS缓冲区就是黄金:只需交换和前置。

所以,它可能是值得的,但你必须研究它。因此:

  • T& T::operator+=(T const&):永远在场
  • T& T::operator+=(T&&):在有意义时启用移动语义

<强>运算符+

这里总是很有用(假设我们正在讨论移动语义很有用的类)。

问题是,operator+产生一个临时的(突然出现)所以它通常必须为此临时创建资源。然而,如果它可以窃取它们而不是创造它们,它肯定会更便宜。

但是,您无需提供所有重载:

  • T operator+(T const&, T const&)
  • T operator+(T&&, T const&)
  • T operator+(T const&, T&&)
  • T operator+(T&&, T&&)(消除歧义所需)

不,您可以重用operator=使用的相同技巧,并在函数签名中创建临时权限(通过复制一个参数)。如果类型是可移动的,那么移动构造函数将被调用,否则它将是复制构造函数,但是因为无论如何你都需要临时,不会损失性能。

inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(T const& left, T right) { right += left; return right; } // commutative
inline T operator+(T left, T&& right) { left += right; return left; } // disambiguation

没有太大的收获(3而不是4)但是,我会尽我所能!

当然,对于字符串,operator+不是可交换的(这就是为什么它是一个不好的重载),所以第二次重载的实际实现需要prepend方法。

编辑:关注Move semantics and operator overloading似乎我有点过于热情了。从Ben Voigt的回答中窃取,我们得到:

inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(const T& left, T&& right) { right += left; return right; }

另一方面,这似乎只适用于交换操作; -不起作用,但可以改编,/%另一方面......

答案 1 :(得分:1)

如果你附加了两个你无法“移动”的字符串,向量等,那就没有意义了。但是如果你要附加,比如链接列表,那么附加列表可能是一个O(1)运算符,如果你愿意牺牲右边,那么它就有意义了。