Click here to Skip to main content
15,860,943 members
Articles / Programming Languages / C++

The Notion of Lvalues and Rvalues

,
Rate me:
Please Sign up or sign in to vote.
4.83/5 (24 votes)
17 Jun 2018CPOL4 min read 50.2K   45   20
This article aims at consolidating the less talked concept of Lvalues and Rvalues

Introduction

Before parsing through the Rvalue references draft in C++11 standard, I never took Lvalues and Rvalues seriously. I even never overhead them among my colleagues or read about them in any C++ books (or may be I would have skipped that part thinking it to be of no importance). The only place I find them often is in compilation errors, like : error C2106: '=' : left operand must be Lvalue. And just by looking at the statement/expression that generated this error, I would understand my stupidity and would graciously correct it with no trouble.

C++
int NextVal_1(int* p) { return *(p+1); }

int* NextVal_2(int* p) { return (p+1); }

int main()
{
  int a[] = {1,2,3,4,5};
  NextVal_1(a) = 9;     //Error. left operand must be l-value
  *NextVal_2(a) = 9;       // Fine. Now a[] = {1,9,3,4,5}
}

I hope with the above code you got what I am saying.

When I went on to read that RValue reference section of C++0x, my vision and confidence started shaking a bit. What I took for granted as Lvalues started appearing as Rvalues. In this article, I will try to simplify and consolidate various concepts related to L & R values. And I feel it necessary to upload this article first, before updating C++11 – A Glance [part 1 of n]. I promise to update it also soon.

Please note that this effort mainly involves gathering scattered information and organizing it in a simple form so that one may not need to Google it again. All credits go to the original authors.

Definitions

An object can be viewed as a region of storage and this storage region can either be just observable or modifiable or both depending on the access specifier associated with it. What I mean is:

C++
int i;             // Here the storage region related to i is both 
                   // Observable and Modifiable
const int j = 8;   // Here the storage region related to j is only Observable
                   // but NOT Modifiable

Before proceeding to the definitions, please memorize this phase: "The notion of Lvalueness or Rvalueness is solely on the expression and nothing to do with the object." Let me simplify it:

C++
double d;

Now d is just an object of type double [and thrusting l/r valueness upon d at this stage is meaningless]. Now once this goes into an expression say like:

C++
d = 3.1414 * 2; 

then the whole concept of l/r values originates. Here, we are having an assignment expression with d on one side and a numerical expression on another side which evaluates to a temporary value and will disappear after semicolon. The 'd' which points to an identifiable memory location is an Lvalue and (3.1414*2) which is a temporary is an Rvalue.

At this point, let's define them

Lvalue: An Lvalue is an expression referring to an object, [which holds some memory location] [The C Programming Language - Kernighan and Ritchie]

Rvalue: The C++ standard defines r-value by exclusion - "Every expression is either an Lvalue or an Rvalue." So an Rvalue is any expression that is not an Lvalue. To be precise, it is an expression that does not necessarily represent an object holding identifiable memory region (it may be temporary).

Points on Lvalues and Rvalues

  1. Numeric literals, such as 3 and 3.14159, are Rvalues. So are character literals, such as 'a'.
  2. An identifier that names an enumeration constant is an Rvalue. For example:
    C++
    enum Color { red, green, blue };
    Color enumColor;
    enumColor = green;     // Fine 
    blue = green;         // Error. blue is an Rvalue
  3. The result of binary + operator is always an Rvalue.
    C++
    m + 1 = n  // Error. As (m+1) is Rvalue.
    
  4. The unary & (address-of) operator requires an Lvalue as its operand. That is, &n is a valid expression only if n is an Lvalue. Thus, an expression such as &3 is an error. Again, 3 does not refer to an object, so it's not addressable. Although the unary & requires an Lvalue as its operand, its result is an Rvalue.
    C++
    int n, *p;
    p = &n;     // Fine 
    &n = p;     // Error: &n is an Rvalue 
  5. In contrast to unary &, unary * produces an lvalue as its result. A non-null(valid) pointer p always points to an object, so *p is an lvalue. For example:
    C++
    int a[N];
    int *p = a;
    *p = 3;         // Fine. 
    
    // Although the result is an Lvalue, the operand can be an Rvalue 
     *(p + 1) = 4; // Fine. (p+1) is an Rvalue
  6. Pre-increment operator expressions results LValues:
    C++
    int nCount = 0;   // nCount represents a persistent object and hence Lvalue
    ++nCount;         // This expression is an Lvalue as this alters 
                      // and then points to nCount object              
     
    // Just to prove that this is an Lvalue, we can do the below operation
    ++nCount = 5;    // Fine.
  7. A function call is an Lvalue if and only if the result type is a reference.
    C++
    int& GetBig(int& a, int& b)    // returning reference to make the function call an Lvalue
    {
        return ( a > b ? a : b );
    }
    
    void main()
    {
        int i = 10, j = 50;
        GetBig( i, j ) *= 5;    
        // Here, j = 250. GetBig() returns the ref of j and it gets multiplied by 5 times.
    } 
  8. A reference is a name, so a reference bound to an Rvalue is itself an Lvalue:
    C++
    int GetBig(int& a, int& b)    // returning an int to make the function call an Rvalue
    {
        return ( a > b ? a : b );
    }
    
    void main()
    {
        int i = 10, j = 50;
        const int& big = GetBig( i, j );
        // Here, I am binding 'big' an Lvalue to the return value from GetBig(), an Rvalue.
    
        int& big2 = GetBig(i, j); // Error. big2 is not binding to the return value as big2 
                                  //        is not const
    } 
  9. Rvalues are temporaries and don't necessarily point to a memory region but they may hold memory in some cases. It is not advisable to catch this address and do any further operations as it would be a booby trap to work on these temporaries.
    C++
    char* fun() { return "Hellow"; } 
    
    int main()
     { 
          char* q = fun();
          q[0]='h';     // Exception is thrown here as fun() returns an temporary memory 
                        // and we are trying to access it !!!
     }
  10. Post-increment operator expressions results RValues:
    C++
    int nCount = 0;  // nCount represents a persistent object and hence Lvalue
    nCount++         // This expression is a Rvalue as it copies the value of the 
                     // persistent object, alters it and then returns the temporary copy.
    
    // Just to prove that this is an Rvalue, we can not do the below operation
    nCount++ = 5; //Error

By summarizing the above points, we can blindly state that: If we can take address of an expression (for further operations) safely, then it is a lvalue expression, else it is an rvalue expression. It makes sense right, as it is preposterous to carry on with a temporary.

Note: Both Lvalues and Rvalues could be modifiable or non-modifiable. Here are the examples:

C++
string strName("Hello");                           // modifiable lvalue
const string strConstName("Hello");                       // const lvalue
string JunkFunction() { return "Hellow World"; /*catch this properly*/}//modifiable rvalue
const string Fun() { return "Hellow World"; }               // const rvalue 

Conversion between Lvalues and Rvalues

Can an Lvalue appear in a context that requires an Rvalue? YES, it can. For example:

C++
int a, b;
a = 8;
b = 5;
a = b;

This = expression uses the Lvalue sub-expression b as Rvalue. In this case, the compiler performs what is called lvalue-to-rvalue conversion to obtain the value stored in b.

Now, can an r-value appear in a context that requires an l-value. NO, it can't.

C++
3 = a // Error. Here 3 which is an RValue is appearing in the context where
        //        Lvalue is required

Acknowledgments

Thanks to Clement Emerson for readily helping me in gathering and organizing this information.

External Resources

  1. http://msdn.microsoft.com/en-us/library/f90831hc.aspx

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
India India
_____________________________________________________________

Did my masters from IIT-M in Advanced Manufacturing Technology and working mainly on C++ in CAD domain from 2004 onwards.
Working on web technologies using Angular 7.0 and above, HTML5, CSS3 from 2015.

Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThank you Pin
Richard Andrew x648-Feb-14 13:06
professionalRichard Andrew x648-Feb-14 13:06 
GeneralRe: Thank you Pin
Lakamraju Raghuram10-Feb-14 0:30
Lakamraju Raghuram10-Feb-14 0:30 
SuggestionComment on #8 Pin
ephisino19-Jan-12 3:56
ephisino19-Jan-12 3:56 
GeneralRe: Comment on #8 Pin
Lakamraju Raghuram19-Jan-12 22:53
Lakamraju Raghuram19-Jan-12 22:53 
GeneralRe: Comment on #8 Pin
ephisino20-Jan-12 3:12
ephisino20-Jan-12 3:12 
GeneralRe: Comment on #8 Pin
Lakamraju Raghuram20-Jan-12 5:35
Lakamraju Raghuram20-Jan-12 5:35 
GeneralRe: Comment on #8 Pin
Ivan55025-Jan-12 11:09
Ivan55025-Jan-12 11:09 
GeneralRe: Comment on #8 Pin
Shafi Mohammad25-Jan-12 17:56
Shafi Mohammad25-Jan-12 17:56 
GeneralMy vote of 5 Pin
moragos18-Jan-12 19:44
moragos18-Jan-12 19:44 
GeneralRe: My vote of 5 Pin
Lakamraju Raghuram18-Jan-12 20:11
Lakamraju Raghuram18-Jan-12 20:11 
QuestionAwesome Pin
T800G17-Jan-12 9:10
T800G17-Jan-12 9:10 
GeneralRe: Awesome Pin
Lakamraju Raghuram17-Jan-12 14:41
Lakamraju Raghuram17-Jan-12 14:41 
QuestionWhat L and R stand for Pin
jsc4216-Jan-12 22:38
professionaljsc4216-Jan-12 22:38 
AnswerRe: What L and R stand for Pin
Lakamraju Raghuram16-Jan-12 23:08
Lakamraju Raghuram16-Jan-12 23:08 
GeneralRe: What L and R stand for Pin
Kaisar Haque31-Jan-12 0:35
Kaisar Haque31-Jan-12 0:35 
GeneralMy vote of 5 Pin
kosmoh14-Jan-12 1:05
kosmoh14-Jan-12 1:05 
GeneralRe: My vote of 5 Pin
Lakamraju Raghuram14-Jan-12 7:38
Lakamraju Raghuram14-Jan-12 7:38 
QuestionWhat happened to my message? Pin
PeteBarber12-Jan-12 5:12
PeteBarber12-Jan-12 5:12 
AnswerRe: What happened to my message? Pin
Lakamraju Raghuram12-Jan-12 5:30
Lakamraju Raghuram12-Jan-12 5:30 
GeneralRe: What happened to my message? Pin
T800G17-Jan-12 9:12
T800G17-Jan-12 9:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.