14,265,784 members

# The Notion of Lvalues and Rvalues

Rate this:
17 Jun 2018CPOL
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 `Lvalue`s and `Rvalue`s 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.

```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 `Lvalue`s started appearing as `Rvalue`s. 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:

```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:

`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:

`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 `Rvalue`s. So are character literals, such as '`a`'.
2. An identifier that names an enumeration constant is an `Rvalue`. For example:
```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`.
```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`.
```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:
```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 `LValue`s:
```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.
```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`:
```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. `Rvalue`s 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.
```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 `RValue`s:
```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 `Lvalue`s and `Rvalue`s could be modifiable or non-modifiable. Here are the examples:

```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:

```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.

```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.

## Share

 Software Developer India
_____________________________________________________________

Did my masters from IIT-M in Advanced Manufacturing Technology and working mainly on C++ in CAD domain from 2004 onwards.

 India
No Biography provided

 First Prev Next
 Thank you Richard Andrew x648-Feb-14 13:06 Richard Andrew x64 8-Feb-14 13:06
 Re: Thank you Lakamraju Raghuram10-Feb-14 0:30 Lakamraju Raghuram 10-Feb-14 0:30
 Comment on #8 ephisino19-Jan-12 3:56 ephisino 19-Jan-12 3:56
 Re: Comment on #8 Lakamraju Raghuram19-Jan-12 22:53 Lakamraju Raghuram 19-Jan-12 22:53
 Re: Comment on #8 ephisino20-Jan-12 3:12 ephisino 20-Jan-12 3:12
 Re: Comment on #8 Lakamraju Raghuram20-Jan-12 5:35 Lakamraju Raghuram 20-Jan-12 5:35
 Re: Comment on #8 Ivan55025-Jan-12 11:09 Ivan550 25-Jan-12 11:09
 My vote of 5 moragos18-Jan-12 19:44 moragos 18-Jan-12 19:44
 Re: My vote of 5 Lakamraju Raghuram18-Jan-12 20:11 Lakamraju Raghuram 18-Jan-12 20:11
 Awesome T800G17-Jan-12 9:10 T800G 17-Jan-12 9:10
 Re: Awesome Lakamraju Raghuram17-Jan-12 14:41 Lakamraju Raghuram 17-Jan-12 14:41
 What L and R stand for jsc4216-Jan-12 22:38 jsc42 16-Jan-12 22:38
 Re: What L and R stand for Lakamraju Raghuram16-Jan-12 23:08 Lakamraju Raghuram 16-Jan-12 23:08
 Re: What L and R stand for Kaisar Haque31-Jan-12 0:35 Kaisar Haque 31-Jan-12 0:35
 My vote of 5 kosmoh14-Jan-12 1:05 kosmoh 14-Jan-12 1:05
 Re: My vote of 5 Lakamraju Raghuram14-Jan-12 7:38 Lakamraju Raghuram 14-Jan-12 7:38
 What happened to my message? PeteBarber12-Jan-12 5:12 PeteBarber 12-Jan-12 5:12
 Re: What happened to my message? Lakamraju Raghuram12-Jan-12 5:30 Lakamraju Raghuram 12-Jan-12 5:30
 Re: What happened to my message? T800G17-Jan-12 9:12 T800G 17-Jan-12 9:12
 Last Visit: 17-Aug-19 14:32     Last Update: 17-Aug-19 14:32 Refresh 1