What Is an Lvalue

What is an lvalue?

Pretty simply, an rvalue is when the expression result will not survive past the end of said expression. An lvalue will. This basic principle is what enables move semantics and rvalue references- that you can modify them without issue, because you know that object's life is over.

Please clarify the concept of lvalue and rvalue here

In c the postfix or prefix ++ operators require that the operand is a modifiable lvalue. Both operators perform an lvalue conversion, so the object is no longer an lvalue.

C++ also requires that the operand of the prefix ++ operator is a modifiable lvalue, but the result of the prefix ++ operator is an lvalue. This is not the case for the postfix ++ operator.

Therefore (++(++i)); compiles as the second operation gets an lvalue, but (++(i++)) doesn't.

What is the reasoning behind the naming of lvalue and rvalue?

The standard mentions this:

An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) [...]

An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) [...]

That is, an lvalue was something you could assign to and an rvalue was something you could assign from.

However, this has gradually gotten further and further from the truth. A simple example of an lvalue that you can't assign it is a const variable.

const int x = 5;
x = 6; // Error

You can even have an rvalue appear on the left side of an assignment when you involve operator overloading.

I find it more useful to think of an lvalue as referencing an object stored in memory and an rvalue as just a value (that may have been read from memory). The concepts mirror this idea quite well. Some examples:

  • Lvalue-to-rvalue can be considered the reading of a value from an object in memory.
  • Most operators require lvalue-to-rvalue conversion because they use the value of the object to calculate a result.
  • The address of operator (&) requires an lvalue because you can only take the address of something in memory. It doesn't need to get the value of the object to work out its address.
  • Performing std::move to turn an lvalue expression into an rvalue expression can be thought of as tricking the compiler into thinking the object that's stored in memory is actually just a temporary value.

However, this also doesn't hold up in every situation. It's just a reasonable analogy.

Why is ++x a lvalue and x++ a rvalue?

++x returns a reference to the object you incremented, where as x++ returns a temporary copy of x's old value.

At least this would be the "normal" way by to implement these operators by convention. And all built-in types work this way. And if you've read about lvalues / rvalues then you would see that since the prefix operator returns the named object itself it would be an lvalue, where as the postfix operator returns a copy of a local temporary, which would then qualify as an rvalue.

Note: Also, we have prvalues, xvalues and such now, so it's technically a bit more complicated these days. Look here for more info.

Difference between r value and l value

l-value refers to memory location which identifies an object. l-value may appear as either left hand or right hand side of an assignment operator(=). l-value often represents as identifier.

Expressions referring to modifiable locations are called “modifiable l-values“. A modifiable l-value cannot have an array type, an incomplete type, or a type with the const attribute. For structures and unions to be modifiable lvalues, they must not have any members with the const attribute. The name of the identifier denotes a storage location, while the value of the variable is the value stored at that location.

An identifier is a modifiable lvalue if it refers to a memory location and if its type is arithmetic, structure, union, or pointer. For example, if ptr is a pointer to a storage region, then *ptr is a modifiable l-value that designates the storage region to which ptr points.


r-value refers to data value that is stored at some address in memory. A r-value is an expression that can’t have a value assigned to it which means r-value can appear on right but not on left hand side of an assignment operator(=).

https://www.geeksforgeeks.org/lvalue-and-rvalue-in-c-language/

Is a dereferenced pointer a valid lvalue?

An lvalue is an expression that refers to a region
of storage that can be manipulated.

*p is such an expression that refers to a region of storage. This is different than say 10+=10; because 10 doesn't refer to a region of storage like a variable would.

Requirements for lvalue in C

The C standard defines an lvalue in section 6.3.2.1p1 as follows:

An lvalue is an expression (with an object type other than void) that potentially designates an object; if an lvalue does not designate an object when it is evaluated, the behavior is undefined. When an object is said to have a particular type, the type is specified by the lvalue used to designate the object. A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.

This definition includes arrays, however an array is not a modifiable lvalue.

The result of the indirection operator * is also an lvalue as it refers to an object. This also applies if the resulting object is an array.

The array subscript operator [] also results in an lvalue as x[y] is exactly equivalent to *(x + y).

The result of the member access operator . and pointer-to-member operator -> is also an lvalue.

A compound literal is an lvalue as well. For example, the following is valid:

int *p = (int [3]){1,2,3};
p[0] = 4;


Related Topics



Leave a reply



Submit