C++: Are lvalue and rvalue interchangeable? [duplicate] - c++

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 "&"?

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.

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

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.

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.

Related

If I pass an rvalue into a function with T&&, in some cases I can change the value, in other cases I can't, why? [duplicate]

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 "&"?
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.
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
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.
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.

rvalue parameter does not behaving like an rvalue [duplicate]

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 "&"?
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.
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
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.
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.

rvalue behaving as a lvalue [duplicate]

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 "&"?
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.
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
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.
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.

r-value parameters in a function

I was wondering about a c++ behaviour when an r-value is passed among functions.
Look at this simple code:
#include <string>
void foo(std::string&& str) {
// Accept a rvalue of str
}
void bar(std::string&& str) {
// foo(str); // Does not compile. Compiler says cannot bind lvalue into rvalue.
foo(std::move(str)); // It feels like a re-casting into a r-value?
}
int main(int argc, char *argv[]) {
bar(std::string("c++_rvalue"));
return 0;
}
I know when I'm inside bar function I need to use move function in order to invoke foo function. My question now is why?
When I'm inside the bar function the variable str should already be an r-value, but the compiler acts like it is a l-value.
Can somebody quote some reference to the standard about this behaviour?
Thanks!
str is a rvalue reference, i.e. it is a reference only to rvalues. But it is still a reference, which is a lvalue. You can use str as a variable, which also implies that it is an lvalue, not a temporary rvalue.
An lvalue is, according to §3.10.1.1:
An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [ Example: If E is an expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue. —end example ]
And an rvalue is, according to §3.10.1.4:
An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment
expression) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.
Based on this, str is not a temporary object, and it is associated with an object (with the object called str), and so it is not an rvalue.
The example for the lvalue uses a pointer, but it is the same thing for references, and naturally for rvalue references (which are only a special type of references).
So, in your example, str is an lvalue, so you have to std::move it to call foo (which only accepts rvalues, not lvalues).
The "rvalue" in "rvalue reference" refers to the kind of value that the reference can bind to:
lvalue references can bind to lvalues
rvalue references can bind to rvalues
(+ a bit more)
That's all there's to it. Importantly, it does not refer to the value that get when you use the reference. Once you have a reference variable (any kind of reference!), the id-expression naming that variable is always an lvalue. Rvalues occur in the wild only as either temporary values, or as the values of function call expressions, or as the value of a cast expression, or as the result of decay or of this.
There's a certain analogy here with dereferencing a pointer: dereferencing a pointer is always an lvalue, no matter how that pointer was obtained: *p, *(p + 1), *f() are all lvalues. It doesn't matter how you came by the thing; once you have it, it's an lvalue.
Stepping back a bit, maybe the most interesting aspect of all this is that rvalue references are a mechanism to convert an rvalue into an lvalue. No such mechanism had existed prior to C++11 that produced mutable lvalues. While lvalue-to-rvalue conversion has been part of the language since its very beginnings, it took much longer to discover the need for rvalue-to-lvalue conversion.
My question now is why?
I'm adding another answer because I want to emphasize an answer to the "why".
Even though named rvalue references can bind to an rvalue, they are treated as lvalues when used. For example:
struct A {};
void h(const A&);
void h(A&&);
void g(const A&);
void g(A&&);
void f(A&& a)
{
g(a); // calls g(const A&)
h(a); // calls h(const A&)
}
Although an rvalue can bind to the a parameter of f(), once bound, a is now treated as an lvalue. In particular, calls to the overloaded functions g() and h() resolve to the const A& (lvalue) overloads. Treating a as an rvalue within f would lead to error prone code: First the "move version" of g() would be called, which would likely pilfer a, and then the pilfered a would be sent to the move overload of h().
Reference.

Rvalue Reference is Treated as an Lvalue?

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 "&"?
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.
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
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.
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.