使用右值引用重载加法运算符作为左手操作数被认为是一种好习惯吗?

Key*_*hsh 3 c++ operator-overloading rvalue-reference c++11

假设str是一个用于存储字符串值的类,它会使加法运算符重载以支持字符串连接.像这样:

str operator+(const str &a,const str &b);
Run Code Online (Sandbox Code Playgroud)

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

str s=str("Hel") + str("lo ") + str("Wor") + str("ld!");
Run Code Online (Sandbox Code Playgroud)

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

str &&operator+(str &&a,const str &b){
   a+=b;
   return std::move(a);
}
Run Code Online (Sandbox Code Playgroud)

通过重载此运算符,然后提到的语句将只创建一个临时对象,并且后续添加将仅连接到该临时对象.

我的问题是,这种方法是否是解决此问题的正确方法?

Yak*_*ont 5

通常可以有效地移动字符串.

因此,您operator+应该返回str不是str&&.这意味着

str const& bob = str1 + str2;
Run Code Online (Sandbox Code Playgroud)

不会破坏,或更合理:

for(char c : str1 + str2)
Run Code Online (Sandbox Code Playgroud)

不会打破可怕的.

其次,只需str按价值计算.如果它是一个右值,它将被移入(便宜).如果它是左值,它将被复制(然后扩展,然后返回).还便宜.

str operator+( str lhs, str const& rhs )
Run Code Online (Sandbox Code Playgroud)

最后,您可以将rhs设置为可转换为str(或有效添加到 - str)的任何模板类型,以删除可能无用的转换.

特别是

str a = str("Hello") + " world";
Run Code Online (Sandbox Code Playgroud)

应该构造"Hello",然后附加" world"而不构造另一个str对象,然后将结果移动到a.

你可以编写一个+左右对称地处理rvalues,但这是有效的,并且具有讽刺意味的是链接+将rvalues放在左边,因为链接如何+绑定它的参数.

最后,您可以一直到表达式模板,并且在分配结果之前几乎不做任何事情.这有危险,对于像玩具弦类这样简单的东西是不值得的.如果您正在编写一个严肃的字符串类,那么在您完成其他一些改进之后可能是值得的.