通用引用作为参数和返回类型

时间:2018-07-13 15:35:45

标签: c++11 c++14 move-semantics

通用引用作为参数或返回类型

我阅读了几篇有关通用引用的文章,但我仍然不明白在哪种情况下,除了move构造函数之外,我可能还需要将其用作参数类型。有人可以启发我吗?

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

在什么情况下,我想拥有一个简单的Bar&无法解决的问题?

何时使用std :: move

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

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

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

在这种情况下,我可能会受益于RVO,所以我什至应该考虑使用std :: move获得结果吗?非常感谢!

1 个答案:

答案 0 :(得分:1)

通用参考

您提供的示例实际上并未使用通用引用,它们只是r值引用。在语法上,通用引用是对推导模板类型的参数的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

还将任何引用返回给局部变量是错误的。

使用r值引用而不是按值传递的唯一原因是允许移动而不实际将其移动一次:

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

每次要移动变量,即使它已经是r值引用,您都需要使用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!
}