是和不是。
运算符+=
移动语义不一定有帮助operator+=
一般来说,因为您已经在修改左侧参数(this
),所以大多数情况下您已经拥有可以使用的资源。
不过,作为一种优化,这可能是值得的。想象一个std::string
其默认构造函数不分配任何内存的实现。然后std::string::operator+=(std::string&&)
可以简单地从 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
虽然收获不大(从 4 变成 3),但好吧,我会尽力而为!
当然,对于字符串来说,operator+
不可交换(这就是为什么它是一个糟糕的重载),因此第二个重载的实际实现将需要prepend
method.
EDIT: 下列的移动语义和运算符重载看来我有点过于热情了。借鉴 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; }
另一方面,这似乎只适用于交换运算;-
不是这样工作的,但可能可以调整,/
and %
另一方面...