Difference between lvalue reference and rvalue reference - c++

I have been studying addition of rvalue reference in C++11. It wasn't straightforward but I feel like I am finally starting to get a grasp of it. However there is one particular instance where I am confused. Specifically I don't get what is the meaning of 'b' in this example:
int a = 27;
int&& b = 27;
EDIT: I know that int a = 27 is an lvalue not lvalue reference.
Also what I looking for is not what int&& b = 27 is but what is it meaning intuitively. I am confused because I thought that rvalues where not addressable, but here we have a reference to rvalue which means we can adress it. So how come it is still an rvalue?

int a = 27; is a statement, and is neither an lvalue nor an rvalue. It defines the name a, which can be used as an lvalue expression, of type int.
int&& b = 27; is also a statement and the name b is used as an lvalue expression of type int&&, and permits a conversion to an xvalue expression of type int

but here we have a reference to rvalue which means we can adress it. So how come it is still an rvalue?
Given int&& b = 27;, a temporary int is constructed from 27 and then b binds to the temporary. (And the lifetime of the temporary is extended to the lifetime of b.) After that if you get the address like &b you'll get the address of the temporary.
BTW b is an lvalue itself.
Temporary objects are created when a prvalue is materialized so that it can be used as a glvalue, which occurs (since C++17) in the following situations:
binding a reference to a prvalue
BTW: It's not special for rvalue reference; same thing happens for const int& b = 27;.

B is rvalue reference and you can assign only rvalue to it.

Related

Can Lvalue Reference be bounded to Rvalue Reference? What will happen during the process?

I am trying to figure out the meaning of the following snippet:
int main() {
int&& a = 2;
int& b = a; // (*)
}
I know a is an lvalue expression of type "rvalue reference to int", and b is a general variable with type "lvalue reference to int". However, the initialization (*) of b seems weird. Since the type of a is not an int, it cannot match the type that b refers to. Can anyone explain this result? Is there any implicit conversion happening during the initialization (*)? Or is there any concept or keyword that I missed?
The code can be compiled and run successfully in here.
Any reference acts as if it's the referred object. Thus when you bind a reference b to another reference a, you actually bind it to the object a refers to.
One tricky part is that rvalue reference is an lvalue itself and C++ allows you to bind only lvalue reference to lvalues, thus you won't be able to bind another rvalue reference here:
int&& a = 2;
int&& b = a; // error
Another notable side-effect, is that a in your sample extends the lifetime of the temporary to the end of the given scope (to be precise to the end of a reference lifetime)

What's the difference between an ordinary rvalue reference and one returned by std::forward?

I can't do this:
int &&q = 7;
int &&r = q;
//Error Message:
//cannot convert from 'int' to 'int &&'
//You cannot bind an lvalue to an rvalue reference
If I understand correctly, when initializing an rvalue reference, there's a temporary variable got initialized too. So int &&q = 7; can be considered as:
int temp = 7;
int &&q = temp;
And when using a reference on the right side, I am actually using the referee. So int &&r = q; can be considered as:
int &&r = temp; //bind an lvalue to an rvalue reference, cause error, understandable
So above is how I understand the compiler error occurs.
Why adding std::forward can solve that?
int &&q = 7;
int &&r = std::forward<int>(q);
I know the std::forward always returns an rvalue reference, how is the reference returned by std::forward different from int&&q?
how is the reference returned by std::forward different from int&&q ?
Their value categories are different. And note that types and value categories are different things.
q is a named variable, it's qualified as lvalue, so it can't be bound to rvalue reference.
(emphasis mine)
the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
While rvalue reference returned from function is qualified as xvalue, which belongs to rvalue.
a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as std::move(x);
The difference between the expressions q and std::forward<int>(q) is that the former is an lvalue, while the latter is an rvalue (of fundamental category xvalue).
I've addressed similar concerns in this answer: the point is that q as an expression is an lvalue, because it has a name. std::forward<int>(q) (or the equivalent std::move(q)) are expressions which don't have names, and since they return (unnamed) rvalue references, they are xvalues, which is a subcategory of rvalue and can thus bind to an rvalue reference.

What is the difference between rvalue reference and xvalue?

I'm new to C++ and this is my first question here so bear with me please ... I have been reading about lvalue and rvalue for a while and I think I understand most of it but there is bit that still confuses me ... so my question will be specific
rvalue references are considered lvalue (this part I understand) but functions that return rvalue references are considered rvalue (or xvalue to be specific) for instance:
int x = 32;
int& Lref = x; // Lref is lvalue ... ok
int& funcA(); // calling funcA() is lvalue ... ok
int&& Rref = 32; // Rref is lvalue ... ok I got this
int&& funcB(); // calling funcB() is rvalue ... Why?
So the question is: why calling funcB() which return rvalue reference is considered rvalue ?
Thanks in advance.
To answer the titular question, "rvalue reference" is a kind of type, while "xvalue" is a kind of expression.
rvalue references are considered lvalue (this part I understand)
They are not. Rvalue references are types, types are not expressions and so cannot be "considered lvalue". What you're referring to is the fact that if an expression consists solely of the name of a variable of type T&&, then it is an lvalue expression of type T.
why calling funcB() which return rvalue reference is considered rvalue
The most straightforward answer would be "by definition". A function call expression where the function's return type is T&& is an xvalue expression of type T. As for motivation, this is exactly what makes std::move do what it does: imbue any expression with the ability to be moved from (also known as "rvalue category" - see http://en.cppreference.com/w/cpp/language/value_category ).
Generally, "object" returned by a function are created on the stack part associated to the function itself. That is it, the value returned have to be copied (or moved) to a new object and this object is an rvalue.
In your code, you did a mistake for the lref. 32 is a rvalue reference.
To be simple, lvalue reference are object that we can obtain an address. We can't get the address of a rvalue reference.
int a = 50;
int &b = a; // Ok because we can get the address of a
int &c = 50; // Error we can't get the address of 50
int &&d = 50; // It is ok
And it works as well with "object".
Take for example a code with an unique_ptr which is not copyable.
std::unique_ptr<int> foo() {
auto ptr = std::make_unique<int>(5);
return ptr;
}
auto a = foo(); // is correct, the ptr will be moved because it is a rvalue
This function must return an rvalue to be correct. (Normally, the compiler when you don't specifize if it a lvalue or rvalue will use an rvalue reference).
Maybe you could take a look at :
http://en.cppreference.com/w/cpp/language/value_category
If it is unclear, let me know

binding a lvalue expression of type T&&

In the last few days I've been trying to grasp an apparently trivial principle behind lvalue/rvalue references. Let us define a new rvalue reference:
int&& x = 12;
x is therefore an lvalue expression of type int&&. Since x is a lvalue, it can be bound to a lvalue reference of the same type, i.e., a lvalue reference of type int&&. Such a lvalue reference would be defined as:
int&& & ref_x = x; // non-working code, just for the sake of explanation
Of course, it is not possible to explicitly define a reference to a reference, and the correct way to perform the binding is as follows:
int& ref_x = x;
C++ Primer reports the following about using references as initializers:
when we use a reference as an initializer, we are really using the
object to which the reference is bound
On the other hand, the lvalue reference must match the type of the lvalue expression. What am I missing? Is reference collapsing involved in this case?
Thanks.
No, x (as an expression) is an expression of type int. The type of the value of an expression is never a reference. In fact, x is also an lvalue, since it is a named thing.
Also, there are no references to references, for the same reason: References bind to values, and values are never references.
If you're ever confused, just keep telling yourself: The value of an expression is always an object type. Whether the value category of an expression is l or r only determines what sort of things the value can bind to; it has no effect on its type.

Is it necessary to have a temporary or a literal to have an rvalue?

This question asks if all temporaries are rvalue.
The answer is no, because if we consider this expression:
const int &ri = 2 + 3;
then, the very same temporary (2 + 3), which is an rvalue here, can be used
as an lvalue in a subsequent expression:
const int *pi = &ri;
so this temporary is not (only) an rvalue.
The logic statement temporary ==> rvalue is then false.
However, we cannot write
const int &ri = &(2 + 3); // illegal, 2 + 3 -> temporary -> rvalue
or
int *i = &4; // illegal, 4 is an rvalue (literal)
or
int foo();
int *i = &foo(); // illegal, foo() -> temporary -> rvalue
Thus my question is, can we generate an rvalue in a certain expression without
having a temporary or a literal? Is rvalue ==> (temporary or literal) true?
Expressions that yield temporary objects are r-values. There's a special rule which allows const-references and r-value references to bind to r-values, and this extends the lifetime of the temporary object to that of the reference (see 12.2(5)), but that does not make the temporary-object expression any less of an r-value.
However, once bound to a reference, the reference variable itself has a name, and thus the reference expression is an l-lvalue.
Don't confuse expressions, variables and objects.
The rvalue and lvalue attributes apply to expressions, not to objects. An expression can be either an lvalue or an rvalue. Oversimplifying a expression that yields a value is an rvalue-expression and an expression that yields an object is an lvalue-expression. The lvalue to rvalue conversion is the act of reading the value out of an object.
A expression that yields a temporary and a literal are both rvalue-expressions they represent a value not an actual object.
In your example:
const int &ri = 2 + 3;
const int *pi = &ri;
The expression 2+3 is an rvalue-expression used to initialize a constant reference. That, according to the language implies the extension of the lifetime of the temporary beyond the current expression and until the reference goes out of scope. After that, in the second expression, the subexpression ri is an lvalue-expression that refers to the temporary object, whose lifetime has been extended.
Note that there are other ways of creating rvalue expressions with temporaries, for example calling a member that yields a reference:
struct test {
test& thisTest() { return *this; }
};
test foo();
... foo().thisTest()
The subexpression foo() is an rvalue-expression, but the expression foo().thisTest() is an lvalue-expression. Both of them refer to a temporary object that will disappear at the end of the full expression.