Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is ++x a lvalue and x++ a rvalue? [duplicate]

Tags:

c++

c++11

So I've been reading up on lvalue and rvalues and I'm a bit confused about the difference between ++x and x++ when it comes to this categorization.

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

like image 951
samuelnj Avatar asked Jun 11 '18 17:06

samuelnj


People also ask

What is the relationship between lvalue and rvalue?

An lvalue (locator value) represents an object that occupies some identifiable location in memory (i.e. has an address). rvalues are defined by exclusion. Every expression is either an lvalue or an rvalue, so, an rvalue is an expression that does not represent an object occupying some identifiable location in memory.

What is the point of rvalue reference?

Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.

What is a variable What is the difference between rvalue and lvalue of a variable?

Lvalues and rvalues are fundamental to C++ expressions. Put simply, an lvalue is an object reference and an rvalue is a value. The difference between lvalues and rvalues plays a role in the writing and understanding of expressions.

Can you take the address of an R value?

rvalue — The expression that refers to a disposable temporary object so they can't be manipulated at the place they are created and are soon to be destroyed. An address can not be taken of rvalues. An rvalue has no name as its a temporary value.


3 Answers

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

like image 89
Carl Avatar answered Oct 16 '22 23:10

Carl


C++ (as opposed to C) is a devoted lvalue-preserving language: it strives to painstakingly preserve the "lvalueness" of an expression whenever it is possible.

  • It is very easy to preserve the "lvalueness" of pre-increment: just increment the operand and return it as an lvalue. Done. The returned lvalue will contain exactly the result it is supposed to contain: the new (incremented) value of the operand.

  • And at the same time it is virtually impossible to preserve "lvalueness" of post-increment: by definition, the result of post-increment is the old (original) value of the operand. If you attempt to return an lvalue from post-increment, you will have to somehow simultaneously ensure two things: 1) the lvalue is incremented, 2) the calling code sees the old value when it looks into that same lvalue (!). This combination of requirements is so contradictory that is basically impossible to implement in C++ object model.

    In order to implement the proper post-increment behavior one has to make sure that the calling code does not look directly into the operand, but rather looks into some conceptual or physical "proxy" that makes the calling code to "see" the old value of the operand. That proxy might be a temporary object that holds the old value. Or that proxy might be something that generates the old value on the fly by subtracting 1 from the new value. In any case, that proxy is what prevents the calling code from accessing the original lvalue.

This is why C++ takes advantage of the easily achievable opportunity to preserve "lvalueness" of pre-increment, but concedes to the impossibility to achieve the same with post-increment. In case of post-increment it is just not worth the effort to deviate from classic standard C behavior, which tends to discard "lvalueness" quickly and happily.

like image 20
AnT Avatar answered Oct 16 '22 21:10

AnT


Maybe writing down the workings in pseudo-code of the operators for int makes it more clear:

prefix:

int& Prefix(int& val)
{
  int& value = val;
  value += 1;
  return value;
}

postfix:

int Postfix(int& val)
{
  int oldValue = val;
  val += 1;
  return oldValue; 
}

The difference is in what is returned by the two operators, one by value and one by reference.

like image 30
Hatted Rooster Avatar answered Oct 16 '22 23:10

Hatted Rooster