通用引用作为参数和 return 类型

universal reference as parameter and return type

通用引用作为参数或return类型

我阅读了一些关于通用引用的文章,但我仍然不明白在哪些情况下我可能需要将它用作移动构造函数之外的参数类型。有没有大佬解惑一下?

void Foo(Bar&& x);
Bar&& Foo();

在什么情况下我会想要用一个简单的 Bar& 来移动一些东西无法解决的问题?

什么时候使用std::move

当需要显式 std::move 时(对于参数和 return 类型),有人可以解释一下吗?在什么情况下我可以期望编译器在优化阶段自动使用它?例如

struct A { A(A&& src) ... };

A Foo()
{
    A a;
    ...
    return a;
}

在这种情况下,我可能会受益于 RVO,那么我是否应该考虑使用 std::move 作为结果?非常感谢!

通用引用

您提供的示例实际上并未使用通用引用,那些只是右值引用。从句法上讲,通用引用是对推导模板类型参数的右值引用:

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!
}