Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why rvalue reference binding to xvalue doesn't work in my code?

I tried to understand lvalue and rvalue in C++11. So I wrote a test code:

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
}

It works pretty well, so I inserted std::cout to print results.

#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; causes a Runtime Error, but I don't know why it makes an error.

I think the return value of baz() would be xvalue, so its lifetime is prolonged. But when I tried to access its value, the error occurs. Why?

like image 773
Seokmin Hong Avatar asked Jul 11 '17 09:07

Seokmin Hong


People also ask

How do you pass rvalue reference to a function?

If you want pass parameter as rvalue reference,use std::move() or just pass rvalue to your function.

Can rvalue bind to lvalue?

By default, the compiler cannot bind a non-const or volatile lvalue reference to an rvalue.

Can you pass an lvalue to an rvalue reference?

Explanation: If you pass an lvalue T to enqueue , U will deduce to T& , and the forward will pass it along as an lvalue, and you'll get the copy behavior you want. If you pass an rvalue T to enqueue , U will deduce to T , and the forward will pass it along as an rvalue, and you'll get the move behavior you want.

How do I get rvalue reference?

An rvalue reference is formed by placing an && after some type. An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary (an rvalue), whereas you can not bind a (non const) lvalue reference to an rvalue.


1 Answers

I think the return value of baz() would be xvalue, so its lifetime is prolonged.

At first what baz() returns is always a dangling reference.

For int&& baz() { return 10; }, the lifetime of the temporary is not extended. It's constructed inside the function and will be destroyed when get out of the function, then baz() always returns a dangling reference.

a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.

Then for int&& rr5 = baz();, rr5 is a dangling reference too; deference on it leads to UB and anything is possible.

On the other hand, if you change baz() to return-by-value, everything would be fine; the return value is copied and then bound to rr5, then the lifetime of the temporary is extended to the lifetime of rr5.

LIVE

like image 146
songyuanyao Avatar answered Oct 13 '22 09:10

songyuanyao