使用右值引用作为其左侧操作数来重载加法运算符是否被认为是一种好的做法?

Is overloading the addition operator with an rvalue reference as its left hand operand considered as a good practice?

假设 str 是一个 class 用于存储字符串值,它将重载加法运算符以支持字符串连接。像这样:

str operator+(const str &a,const str &b);

但问题是如果我们有这样的事情:

str s=str("Hel") + str("lo ") + str("Wor") + str("ld!");

然后它会创建 3 个临时对象(因为我们在每次添加时都会得到一个新对象),这在这个上下文中并不是真正需要的。 此问题的一个简单解决方案可能是重载一个新的加法运算符,该运算符接受右值引用作为其左操作数,并且 returns 该操作数在将其与右操作数连接后也作为右值引用。像这样:

str &&operator+(str &&a,const str &b){
   a+=b;
   return std::move(a);
}

通过重载此运算符,上述语句将仅创建一个临时对象,而后续添加将仅连接到该临时对象。

我的问题是,这个方法是解决这个问题的正确方法吗?

通常可以高效地移动字符串。

因此,您的 operator+ 应该 return str 而不是 str&&。这意味着

str const& bob = str1 + str2;

不会坏得很厉害,或者更合理地说:

for(char c : str1 + str2)

不会坏得很厉害。

其次,按值取一个str。如果它是右值,它将被移入(便宜)。如果它是一个左值,它将被复制(然后扩展,然后 returned)。还便宜。

str operator+( str lhs, str const& rhs )

最后,您可以使 rhs 成为任何可转换为 str(或有效添加为 str)的模板类型,以删除可能无用的转换。

特别是

str a = str("Hello") + " world";

应该构造 "Hello",然后在不构造另一个 str 对象的情况下追加 " world",然后将该结果移动到 a.

您可以编写一个 + 来对称地处理左右两侧的右值,但这是可行的,并且具有讽刺意味的是,链式 + 将右值放在左侧,因为链式 + 绑定其参数。

最后,您可以一直使用表达式模板,在分配结果之前(几乎)什么都不做。这有危险,对于像玩具绳这样简单的东西来说是不值得的 class。如果你正在写一个严肃的字符链 class,在你做了很多其他改进之后可能是值得的。