我想知道在重载operator+和/或operator+=时,什么情况下使用移动语义是有意义的。虽然这个问题中已经解释了如何做到这一点,但我无法理解为什么要这样做。让我们考虑operator+=。如果我只是通过引用传递右侧,并对左侧对象进行适当的更改,则根本没有不必要的副本。因此,我们回到同一个问题:在这种情况下使用移动语义是否有益呢?
我想知道在重载operator+和/或operator+=时,什么情况下使用移动语义是有意义的。虽然这个问题中已经解释了如何做到这一点,但我无法理解为什么要这样做。让我们考虑operator+=。如果我只是通过引用传递右侧,并对左侧对象进行适当的更改,则根本没有不必要的副本。因此,我们回到同一个问题:在这种情况下使用移动语义是否有益呢?
是和不是。
operator+=
移动语义通常对于operator+=
并没有什么帮助,因为您已经修改了左侧参数(this
),所以大多数情况下您已经有资源可供使用。
但是,作为一种优化,它可能是值得的。想象一个std::string
实现,其默认构造函数不分配任何内存。然后,std::string::operator+=(std::string&&)
可以简单地从RHS中窃取资源。或者想象一下,RHS缓冲区足够大,可以容纳所有内容,但LHS不行,那么如果您可以使用RHS缓冲区,您就可以轻松解决:只需交换并添加前缀。
因此,这可能是值得的,但您必须进行研究。因此:
T& T::operator+=(T const&)
:始终存在T& T::operator+=(T&&)
:在适当时启用移动语义operator+
如果我们讨论的是适用于移动语义的类,则这里总是有用的。
问题在于,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
视为右值。 - Johannes Schaub - litboperator-
时已经出现了问题,而使用/
和%
时则更加糟糕。 - Matthieu M.-
可以(通常)执行 right = -right; right += left;
。并且通过 /
可能会使用 right = recip(right); right *= left;
。 但是 %
不起作用。或者 <<
或 >>
。对于这些情况,您只需省略第二个重载,并且不关心右操作数是否为右值引用。 - Ben Voigt
+
,我可能同意(不过,为什么不编写一个数字或矩阵库呢?),但<<
和>>
只是 C++ 中流的惯用法。 - Matthieu M.<<
和>>
,那是一种特殊情况,你可以重载运算符以符合库(伪代码1))。 - enobayram