【问题标题】:Does it make sense to use move semantics for operator+ and/or operator+=?对 operator+ 和/或 operator+= 使用移动语义是否有意义?
【发布时间】:2012-04-08 17:17:47
【问题描述】:

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

【问题讨论】:

  • 重载运算符通常是个坏主意。因为:1) 如果这样做显然是一个好案例,那么可能有一个库已经为您实现了它。 2) 如果这样做显然不是一个好案例,那么这样做可能是一个非常糟糕的案例。
  • @enobayram 如果您对重载运算符很敏感,请将其设为append 成员函数。现在你仍然可以回答这个问题。
  • @enobayram,这根本没有意义。按照这种逻辑,编写任何类型的代码通常都是一个坏主意。
  • @enobayram:取决于。我可能同意+(不过,为什么我不应该编写数字或矩阵库?)但<<>> 只是流的惯用C++。
  • @TonyK 编写已经编写好的代码通常是个坏主意。

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


【解决方案1】:

是和不是。

操作员+=

一般来说,移动语义不一定对operator+= 有帮助,因为您已经在修改左侧参数 (this),因此大多数时候您已经有资源可以使用。

不过,作为一种优化,它可能是值得的。想象一个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; }

另一方面,这似乎只适用于交换运算; - 不是这样工作的,但可能可以适应,另一方面,/%...

【讨论】:

  • 最好使用right += left; return right; 使其在返回时将right 视为右值。
  • @JohannesSchaub-litb:我可以假设您在谈论最后一个案例吗?我也想知道这一点,是否值得 T&& T::operator+()&& 重载。
  • 澄清一下;您是否根据@JohannesSchaub-litb 的 cmets 更新了答案?我有点困惑。
  • @BenVoigt:是的,但是有些事情让我很困扰。所有的例子都是用可交换的操作完成的,但并不是所有的操作都是可交换的。它已经在与operator- 的接缝处磨损,并与/% 真正分崩离析。
  • @Moia:我知道的移动语义或运算符没有变化,这会影响这个答案;所以我希望它仍然是准确的(无论好坏)。不过,我想 2 个运营商也不错。
【解决方案2】:

如果您要附加两个无法“移动”的字符串、向量等,那就没有意义了。但是,如果您要追加链接列表,其中追加列表可能是 O(1) 运算符,如果您愿意牺牲右手边,那么这是有道理的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-21
    • 1970-01-01
    • 2016-08-12
    • 1970-01-01
    • 1970-01-01
    • 2014-01-23
    • 1970-01-01
    相关资源
    最近更新 更多