【问题标题】:universal reference as parameter and return type通用引用作为参数和返回类型
【发布时间】:2018-12-22 00:55:00
【问题描述】:

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

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

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 作为结果?非常感谢!

【问题讨论】:

  • 通用引用是推导类型的时候。你不用推断类型,Bar&& 只是一个右值引用。

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


【解决方案1】:

通用参考

您提供的示例实际上并未使用通用引用,这些只是 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!
}

【讨论】:

  • 很棒的解释!谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 2020-11-22
  • 2014-06-23
  • 1970-01-01
  • 2022-01-16
相关资源
最近更新 更多