通用参考
您提供的示例实际上并未使用通用引用,这些只是 r 值引用。从句法上讲,通用引用是对 duce 模板类型参数的 r 值引用:
template <typename Bar>
void foo(Bar &&bar);
这实际上与常规 r 值引用不同,它用于解决perfect forwarding 问题。但我认为这不是你的问题。
R 值参考
在大多数情况下,当您想将值移入或移出函数时,您可以简单地按值进行:
void foo(Bar b);
...
Bar somebar;
foo(std::move(somebar)); //function argument is move-constructed
/**************************************************************/
Bar foo()
{
Bar somebar;
return somebar; //return value is move-constructed
}
使用左值引用这样做实际上是不正确的:
void foo(Bar &b)
{
Bar somebar = std::move(b); //you "stole" passed value
}
...
Bar somebar;
foo(somebar); //but the caller didn't intend to move his value
将任何引用返回到局部变量也是错误的。
使用右值引用而不是按值传递的唯一原因是允许移动值而不实际移动它一次:
Bar &&Foo::foo()
{
return memberBar;
}
...
Foo f;
Bar b = f.foo(); //"b" will be move-constructed
...
f.foo().doBar(); //returned "Bar" value is just used and not moved at all
何时使用std::move
您每次想要移动变量时都需要使用std::move即使它已经是一个右值引用:
Foo::Foo(Bar &&bar)
: memberBar(std::move(bar)) //still need to move explicitly!
{
}
您不需要在以下情况下需要使用std::move:
- 按值返回局部变量
- 将临时值传递给函数,例如
foo(Bar())
- 传递包括原始类型在内的不可移动类型(没有移动构造函数的类型)
一个常见的错误:
Bar *bar = new Bar();
foo(std::move(bar)); //not needed! nothing to move since the pointer is passed and not the object itself
但是使用条件运算符时:
Bar foo()
{
Bar somebar;
Bar otherbar;
return std::move(true ? somebar : otherbar); //need to move explicitly!
}