是否有任何理由将返回值捕获为rvalue参考

Is there any reason to capture a return-value as an rvalue-reference?

本文关键字:rvalue 参考 返回值 任何 理由 是否      更新时间:2023-10-16

我有一个仅动作的struct Foo,函数 Foo get();

如果我想以可变的方式捕获get的返回值,我有两个选择:

  • 按值(Foo
  • rvalue-Reference(Foo&&

当我通过rvalue-reference捕获时,我会创建一个lvalue,就像按值捕获。

我正在努力看到不同选项之间的观点?

  • 这两个之间是否有之间的区别?

工作示例:

#include <iostream>
struct Foo
{
    Foo(std::string s) : s(std::move(s)) {}
    Foo(Foo&& f)       : s(std::move(f.s)) {}
    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;
    std::string s;
};
Foo get()
{
    return Foo { "hello" };
}
int main()
{
    // capture return value as l-value
    Foo lv1 = get();
    // move into another lvalue
    Foo lv2 = std::move(lv1);
    std::cout << lv2.s << 'n';
    // capture return value as r-value reference
    Foo&& rv1 = get();
    // move into another lvalue
    Foo lv3 = std::move(rv1);
    std::cout << lv3.s << 'n';
    return 0;
}
Foo lv1 = get();

这要求Foo是复制/可移动。

Foo&& rv1 = get();

这不是(至少不到这一代码行; get的实现仍然需要一个)。

即使允许编译器将返回值的副本列入变量,但该表格的副本初始化仍然需要可访问的副本或移动构造函数。

因此,如果您想对Foo的类型施加尽可能少的限制,则可以存储返回值的&&

当然,C 17更改此规则,因此第一个规则不需要复制/移动构造函数。

Foo&&

这将创建对临时值的引用(或存储分配给其的RVALUE参考)。如果它存储了对临时值的引用,则其寿命会扩展值。

Foo

这将存储一个值的副本,无论返回什么。

在C 11和14中,如果无法移动Foo,则将Foo make_foo()分配给Foo类型的变量是非法的。即使省略了移动,也有一个移动(返回值和外部范围中的值已合并了寿命)。

在C 17中,保证省略意味着不存在移动构造器。

Foo x = make_foo(); // Foo make_foo()

C 17中的上述内容保证make_foo()的返回值仅名为x。实际上, make_foo中的临时也可能是 x;具有不同名称的相同对象。不需要移动。

还有其他一些细微的差异。decltype(x)将返回x的声明类型;因此,FooFoo&&取决于

另一个重要区别是它与auto一起使用。

auto&& x = some_function();

这将创建对任何事物的引用。如果some_function返回临时性,它将绑定对其的RVALUE引用并延长其寿命。如果返回参考,x匹配参考的类型。

auto x = some_function();

这会创建一个值,该值可以从some_function返回的内容复制,或者如果some_function的返回值返回临时值。

auto&&在某种意义上是指"只要使它起作用,不要做额外的工作",它可以推断为Foo&&auto的意思是"存储副本"。

在"几乎总是自动"样式中,这些将比显式FooFoo&&更常见。

auto&&永远不会推断为Foo,但可以推断为Foo&&

auto&&的最常见用途,即使在几乎总是自动之外,也是:

for(auto&& x : range)

x成为迭代范围内迭代的一种有效方法,我们不在乎哪种类型的range有很多。另一个常见用途是:

[](auto&& x){ /* some code */ }

lambdas通常用于类型很明显且不值得再次键入的上下文中,例如传递到算法之类的上下文。通过使用auto&&用于参数类型,我们使代码少详细。