2016-11-23 42 views
2

我有一招,只有结构Foo和功能Foo get();是否有任何理由将一个返回值作为右值引用?

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

  • 按值(Foo
  • 通过右值引用(Foo&&

当我通过右值引用创建左值捕获,很像捕获按价值。

我很努力地看到不同选项之间的点?

  • 是否有任意这两个区别?

工作实施例:

#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; 
} 

回答

3
Foo lv1 = get(); 

这要求Foo是复制/移动。

Foo&& rv1 = get(); 

这不(至少,不只要这行代码而言;的get执行可能仍然需要一个)。

即使编译器被允许将返回值的副本隐藏到变量中,但复制此表单的初始化仍然需要存在可访问的副本或移动构造函数。

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

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

2
Foo&& 

这产生到一个临时值的参考(或存储分配给它的右值参考)。如果它存储对临时值的引用,则其生存期会延长该值。

Foo 

这存储了值的副本,不管返回的是什么。

在C++ 11和图14,如果Foo不能移动,分配Foo make_foo()到类型的变量Foo是非法的。这里有一个动作,即使这个动作被消除了(并且返回值和外部范围中的值已经合并了寿命)。

在C++ 17中,有保证的elision意味着不需要移动构造函数。

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返回一个临时值,它会将一个右值引用绑定到它并延长其生存期。如果它返回一个引用,则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 */ } 

lambda表达式经常被用来在上下文,其中类型是显而易见的,不值得再打字,像被传递到算法等。通过将auto&&用于参数类型,我们使代码变得更加冗长。

+0

“如果它存储对临时值的引用,则其生存期会延长该值。” - 只有当返回值是一个prvalue。如果函数返回一个表示临时的xvalue,则会产生一个缺陷。 'Foo && f = std :: move(std :: string {});' –

+0

@ m.m。是的,如果不转变为标准,这很难说得通 – Yakk

相关问题