rvalue and lvalue - krishnaramb/cplusplus GitHub Wiki
An lvalue (locator value) πrepresents an object that occupies some identifiable location in memory (i.e. has an address πΊ).
rvalue are defined by exclusion which means every expression is either an lvalue or an rvalue. Therefore, from the above definition of lvalue, an rvalue is an expression that does not represent an object occupying some identifiable location in memory.
- r-values: can not be on the lhs of assignment
- r-values: don't have an address
- l-values: can be on the lhs of assignment
- l-value: do have an address
lets see one example
int foo() {return 2;}
int main()
{
    foo() = 2;
    return 0;
}when you compile it, you will get error as
prog.cpp: In function 'int main()':
prog.cpp:8:11: error: lvalue required as left operand of assignment
what happens in the following code snippet?
#include <iostream>
using namespace std;
int& foo()
{
    return 2;
}
int main()
{
    foo() = 2;
    return 0;
}
The compiler will complain with rvalue as
prog.cpp: In function 'int& foo()':
prog.cpp:6:12: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
Let's assume we have an integer variable defined and assigned to:
int var;
var = 4;An assignment expects an lvalue as its left operand, and var is an lvalue, because it is an object with an identifiable memory location. On the other hand, the following are invalid:
4 = var;       // ERROR!
(var + 1) = 4; // ERROR!Neither the constant 4, nor the expression var + 1 are lvalues (which makes them rvalues). They're not lvalues because both are temporary results of expressions, which don't have an identifiable memory location (i.e. they can just reside in some temporary register for the duration of the computation). Therefore, assigning to them makes no semantic sense - there's nowhere to assign to.
So it should now be clear what the error message in the first code snippet means. foo returns a temporary value which is an rvalue. Attempting to assign to it is an error, so when seeing foo() = 2; the compiler complains that it expected to see an lvalue on the left-hand-side of the assignment statement.
Not all assignments to results of function calls are invalid, however. For example, C++ references make this possible:
int globalvar = 20;
int& foo()
{
    return globalvar;
}
int main()
{
    foo() = 10;
    return 0;
}Here foo returns a reference, which is an lvalue, so it can be assigned to. Actually, the ability of C++ to return lvalues from functions is important for implementing some overloaded operators. One common example is overloading the brackets operator [] in classes that implement some kind of lookup access. std::map does this:
Initially when lvalues were defined for C, it literally meant "values suitable for left-hand-side of assignment". Later, however, when ISO C added the const keyword, this definition had to be refined. After all:
const int a = 10; // 'a' is an lvalue
a = 10;           // but it can't be assigned!So a further refinement had to be added. Not all lvalues can be assigned to. Those that can are called modifiable lvalues.
Generally speaking, language constructs operating on object values require rvalues as arguments. For example, the binary addition operator '+' takes two rvalues as arguments and returns an rvalue
int a = 1;     // a is an lvalue
int b = 2;     // b is an lvalue
int c = a + b; // + needs rvalues, so a and b are converted to rvalues
               // and an rvalue is returnedAs we've seen earlier, a and b are both lvalues. Therefore, in the third line, they undergo an implicit lvalue-to-rvalue conversion. All lvalues that aren't arrays, functions or of incomplete types can be converted thus to rvalues
What about the other direction? Can rvalues be converted to lvalues? Of course not! This would violate the very nature of an lvalue according to its definition
This doesn't mean that lvalues can't be produced from rvalues by more explicit means. For example, the unary '*' (dereference) operator takes an rvalue argument but produces an lvalue as a result. Consider this valid code:
int arr[] = {1, 2};
int* p = &arr[0];
*(p + 1) = 10;   // OK: p + 1 is an rvalue, but *(p + 1) is an lvalueConversely, the unary address-of operator '&' takes an lvalue argument and produces an rvalue:
int var = 10;
int* bad_addr = &(var + 1); // ERROR: lvalue required as unary '&' operand
int* addr = &var;           // OK: var is an lvalue
&var = 40;                  // ERROR: lvalue required as left operand
                            // of assignmentThe ampersand plays another role in C++. It allows to define reference types. These are called "lvalue references" π.
- Note that Non-const lvalue references cannot be assigned rvalues ππ, since that would require an invalid rvalue-to-lvalue conversion. For examples
int main()
{
 int x= 20;
 int & y = x +2; // ERROR (Non-const lvalue references cannot be assigned rvalues)
 int & y = x;  // OK
 std::cout<<y;
 std::cout<<x;
}
// error: invalid initialization of non-const reference of type 'int&' from an rvalue of
// type 'int'int main()
{
 int x= 20;
 const int & y = x +2; // OK (Constant lvalue references can be assigned rvalues)
 std::cout<<y;
 std::cout<<x;
}
//2220std::string& sref = std::string();  // ERROR: invalid initialization of
                                    // non-const reference of type
                                    // 'std::string&' from an rvalue of
                                    // type 'std::string'- 
Constant lvalue references can be assigned rvalues π π
 Since they're constant, the value can't be modified through the reference and hence there's no problem of modifying an rvalue.
 This makes possible the very common C++ idiom of accepting values by constant references into functions, which avoids unnecessary copying and construction of temporary objects.
int arr[] = {1, 2};
int* p = &arr[0];
*(p + 1) = 10;   // OK: p + 1 is an rvalue, but *(p + 1) is an lvalueThis note has been extracted from ref1
Rvalue references solve at least two problems
- Implementing move semantics
- Perfect forwarding
Suppose X is a class that holds a pointer or handle to some resource, say, m_pResource.
X& X::operator=(cosnt X  & rhs)
{
  // [...]
  // Make a clone of what rhs.m_pResource refers to.
  // Destruct the resource that m_pResource refers to.
  // Attach the clone to m_pResource.
  // [...]
}Now suppose X is used as follows
X foo();
X x;
// perhaps use x in various ways
x = foo();The last line above
- clones the resource from the temporary returned by foo,
- destructs the resource held by xand replaces it with the clone,
- destructs the temporary and thereby releases its resource.
 Rather obviously, it would be ok, and much more efficient, to swap resource pointers (handles) betweenxand the temporary, and then let the temporary's destructor destruct x's original resource
 In other words, in the special case where the right hand side of the assignment is an rvalue, we want the copy assignment operator to act like this:
// [...]
// swap m_pResource and rhs.m_pResource
// [...]
This is called move semantics. With C++11, this conditional behavior can be achieved via an overload.
X& X::operator=(<mystery type> rhs)
{
  // [...]
  // swap this->m_pResource and rhs.m_pResource
  // [...]  
}- Since we're defining an overload of the copy assignment operator, our "mystery type" must essentially be a reference: we certainly want the right hand side to be passed to us by reference.
- Basically we want, when there is a choice between two overloads where one is an ordinary reference and the other is the mystery type, then rvalues must prefer the mystery type, while lvalues must prefer the ordinary reference ππ
- If you now substitute "rvalue reference" for "mystery type" in the above, you're essentially looking at the definition of rvalue references.
- If Xis any type, thenX&&is called an rvalue reference to X.
- For better distinction, the ordinary reference X&is now also called an lvalue reference.
- The most important distinction between r-value and l-value referencing is, when it comes to function overload resolution, lvalues prefer old-style lvalue references, whereas rvalues prefer the new rvalue references
void foo(X& x); // lvalue reference overload
void foo(X&& x); // rvalue reference overload
X x;
X foobar();
foo(x); // argument is lvalue: calls foo(X&)
foo(foobar()); // argument is rvalue: calls foo(X&&)- So the gist is, Rvalue references allow a function to branch at compile time (via overload resolution) on the condition "Am I being called on an lvalue or an rvalue?"
- It is true that you can overload any function in this manner, as shown above. But in the overwhelming majority of cases, this kind of overload should occur only for copy constructors and assignment operators, for the purpose of achieving move semantics
X& X::operator=(const X & rhs); // classical implementation
X& X::operator=(X&& rhs)
{
  // Move semantics: exchange content between this and rhs
  return *this;
}Note, if you implement
void foo(X&);but not
void foo(X&&);then of course the behavior is unchanged: foo can be called on l-values, but not on r-values
But if you implement
void foo(X const &);but not
void foo(X&&);then again, the behavior is unchanged: foo can be called on l-values and r-values, but it is not possible to make it distinguish between l-values and r-values. To make possible distinguish between l-values and r-values, we need to implement following as well
void foo(X&&);Important Note: if you implement void foo(X&&); but neither one of void foo(X&); and void foo(X const &); are implemented, then according to the final version of C++11, foo can be called on r-values, but trying to call it on an l-value will trigger a compile error.
This note has been extracted from ref2