2017-07-11 27 views
13

我试图理解C++ 11中的左值和右值。所以我写了一个测试代码:为什么在我的代码中右值引用绑定到xvalue不起作用?

int x = 10; 
int foo() { return x; } 
int& bar() { return x; } 
int&& baz() { return 10; } 

int main() { 
    int& lr1 = 10;  // error: lvalue references rvalue 
    int& lr2 = x;  // ok 
    int& lr3 = foo(); // error: lvalue references rvalue 
    int& lr4 = bar(); // ok 
    int& lr5 = baz(); // error: lvalue references rvalue 

    int&& rr1 = 10; // ok 
    int&& rr2 = x;  // error: rvalue references lvalue 
    int&& rr3 = foo(); // ok 
    int&& rr4 = bar(); // error: rvalue references lvalue 
    int&& rr5 = baz(); // ok 
} 

它工作的很好,所以我插入了std :: cout来打印结果。

#include <iostream> 

int x= 10; 
int foo() { return x; } 
int& bar() { return x; } 
int&& baz() { return 10; } 

int main() { 
    int& lr1 = 10;  std::cout << lr1 << std::endl; // error 
    int& lr2 = x;  std::cout << lr2 << std::endl; // ok 
    int& lr3 = foo(); std::cout << lr3 << std::endl; // error 
    int& lr4 = bar(); std::cout << lr4 << std::endl; // ok 
    int& lr5 = baz(); std::cout << lr5 << std::endl; // error 

    int&& rr1 = 10; std::cout << rr1 << std::endl; // ok 
    int&& rr2 = x;  std::cout << rr2 << std::endl; // error 
    int&& rr3 = foo(); std::cout << rr3 << std::endl; // ok 
    int&& rr4 = bar(); std::cout << rr4 << std::endl; // error 
    int&& rr5 = baz(); std::cout << rr5 << std::endl; // ERROR!? 
} 

int&& rr5 = baz(); std::cout << rr5;导致运行时错误,但我不知道为什么它使一个错误。

我认为baz()的返回值是x值,所以它的寿命延长。但是当我尝试访问它的值时,会发生错误。为什么?

+6

当发问关于构建错误,请包括实际的错误(全部,完整,未经编辑,复制粘贴文本)的问题身上。 –

+1

对不起。它会产生运行时错误。 –

+2

“xvalue所以它的寿命延长”这将是一个误解。 C++延长了* temporaries *的生存期,而不是左值,右值或前值。它在引用绑定到这样一个临时对象时这样做。表情中没有临时对象。此外,'bar'和'baz'都会调用未定义的行为,一个是通过返回一个对本地对象的引用,另一个是由于无法返回任何内容。 –

回答

18

我认为baz()的返回值是x值,所以它的寿命会延长。

起初什么baz()返回总是一个悬而未决的参考。

对于int&& baz() { return 10; }lifetime of the temporary没有扩展。它是在函数内部构造的,当退出函数时将被销毁,然后baz()总是返回一个悬挂参考。

语句中函数的返回值的临时绑定不会被扩展:它会在返回表达式的末尾被立即销毁。这样的函数总是返回一个悬挂参考。

然后对于int&& rr5 = baz();rr5也是一个悬挂参考;尊重它导致UB和任何事情都是可能的。

另一方面,如果您将baz()更改为按值返回,则一切正常;返回值被复制,然后绑定到rr5,则临时的生命周期延长到rr5的生命周期。

LIVE

+0

临时销毁之前不应该将它保存在'rr5'中吗? – CinCout

+1

@CinCout它必须在'baz()'函数中'移动'才能这样做 –

+3

@CinCout - 'rr5'不存储任何内容。它绑定到一个对象。在绑定发生之前,该对象基本上被销毁了。 – StoryTeller

相关问题