Rvalue Reference is Treated as an Lvalue?

有些话、适合烂在心里 提交于 2019-11-26 00:29:21

问题


I posted this answer: https://stackoverflow.com/a/28459180/2642059 Which contains the following code:

void foo(string&& bar){
    string* temp = &bar;

    cout << *temp << \" @:\" << temp << endl;
}

Is bar an rvalue or an lvalue?

I ask because I obviously cannot take the address of an rvalue, yet I can take the address of an rvalue reference as is done here.

If you can perform any operation on an rvalue reference that you can on an lvalue reference what is the point in differentiating between the two with the \"&&\" instead of just an \"&\"?


回答1:


Is bar an rvalue or an lvalue?

The question answers itself. Whatever has a name is an lvalue(1). So bar is an lvalue. Its type is "rvalue reference to string", but it's an lvalue of that type.

If you want to treat it as an rvalue, you need to apply std::move() to it.


If you can perform any operation on an rvalue reference that you can on an lvalue reference what is the point in differentiating between the two with the "&&" instead of just an "&"?

This depends on your definition of "perform an operation." An lvalue reference and a (named) rvalue reference are pretty much identical in how you can use them in expressions, but they differ a lot in what can bind to them. Lvalues can bind to lvalue references, rvalues can bind to rvalue references (and anything can bind to an lvalue reference to const). That is, you cannot bind an rvalue to an lvalue reference, or vice versa.

Let's talk about a function parameter of rvalue reference type (such as your bar). The important point is not what bar is, but what you know about the value to which bar refers. Since bar is an rvalue reference, you know for certain that whatever bound to it was an rvalue. Which means it's bound to be destroyed when the full expression ends, and you can safely treat it as an rvalue (by stealing its resources etc.).

If you're not the one doing this directly to bar, but just want to pass bar on, you have two options: either you're done with bar, and then you should tell the next one who receives it that it's bound to an rvalue—do std::move(bar). Or you'll need to do some more things with bar, and so you do not want anyone inbetween stealing its resources from under you, so just treat it as an lvalue—bar.

To summarise it: The difference is not in what you can do with the reference once you have it. The difference is what can bind to the reference.


(1) A good rule of thumb, with minor exceptions: enumerators have names, but are rvalues. Classes, namespaces and class templates have names, but aren't values.




回答2:


Is bar an rvalue or an lvalue?

It's an lvalue, as is any expression that names a variable.

If you can perform any operation on an rvalue reference that you can on an lvalue reference what is the point in differentiating between the two with the "&&" instead of just an "&"?

You can only initialise an rvalue reference with an rvalue expression. So you can pass a temporary string to your function, but you can't pass a string variable without explicitly moving from it. This means your function can assume the argument is no longer wanted, and can move from it.

std::string variable;
foo(variable);            // ERROR, can't pass an lvalue
foo(std::move(variable)); // OK, can explicitly move
foo("Hello");             // OK, can move from a temporary



回答3:


Here in this case named rvalue references are lvalues, while if the input type is const named rvalue references then it will be rvalue, here is a simple example:

#include <string>
#include <iostream>

void foo(const std::string&& bar) { 
    std::string* temp = &bar; // compile error, can't get address
    std::cout << *temp << " @:" << temp << std::endl;
}

int main()
{
    foo("test");
    return 0;
}

Hope this is useful.




回答4:


The expression bar is an lvalue. But it is not an "rvalue reference to string". The expression bar is an lvalue reference. You can verify it by adding the following line in foo():

cout << is_lvalue_reference<decltype((bar))>::value << endl; // prints "1" 

But I agree with the rest of the explanation of Angew.

An rvalue reference, after it has been bound to an rvalue, is an lvalue reference. Actually it is not just for function parameters:

string&& a = "some string";
string&& b = a; // ERROR: it does not compile because a is not an rvalue

If you can perform any operation on an rvalue reference that you can on an lvalue reference what is the point in differentiating between the two with the "&&" instead of just an "&"?

An rvalue reference allows us to do some "lvalue operations" before the rvalue expires.



来源:https://stackoverflow.com/questions/28483250/rvalue-reference-is-treated-as-an-lvalue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!