1

If I use a nested increment operator in C++, such as

int a = 1;
int b = (a++)++;

It gives a compile-time error:

error: lvalue required as increment operand

However, if I write

int a = 1;
int b = ++(++a);

The new value of b becomes 3.

What is the reason for this?

  • 2
    The reason is value category. A post increment is only possible on an lvalue, but returns an rvalue. Also, please add information to the question by editing the question, not by posting comments. – super Jul 03 '21 at 19:49
  • But… why even bother… what’s the useful point of even trying to write code like in this question - you’d never write this in production code… would you? – DisappointedByUnaccountableMod Jul 03 '21 at 21:44

2 Answers2

6

(a++) returns a temporary rvalue with an old value of a. There is no postincrement operator available to rvalues.

273K
  • 29,503
  • 10
  • 41
  • 64
  • **What is the value of `b` in "```int a = 1; int b = (a++) + (a++);```"** ??? If it is `2`, then I don't understand all the downvotes on my answer (o_O ) - you say "old value", I say it does not change at all till semi-colon. – Top-Master Jul 03 '21 at 20:07
  • 2
    @Top-Master You updated your answer after my answer. Your example above leads undefined behaviour. – 273K Jul 03 '21 at 20:12
  • Can you define what's undefined? Do you mean the C++ spec let's the compiler do whatever it wants with "`int b = (a++) + (a++);`" code? – Top-Master Jul 03 '21 at 20:16
  • @Top-Master constant is not rvalue. – 273K Jul 03 '21 at 20:16
  • 1
    @Top-Master nothing is done after the `;`. You misunderstood something – 463035818_is_not_an_ai Jul 03 '21 at 20:17
  • @Top-Master Like @S.M said, `b = (a++) + (a++)` is undefined behavior, because C++ doesn't specific the order of evaluation, and it could perform either the first `a++` or the second `a++` first. And it is actually more likely to result to `3` instead of `2`: https://godbolt.org/z/na373bvKG – Ranoiaetep Jul 03 '21 at 20:21
  • But my question was what is the value of `b`, so, no matter which is executed first. (Also, I meant end-of-statement with semi-colon, see the Assembly as proof). – Top-Master Jul 03 '21 at 20:25
  • 1
    @Top-Master assembly cannot prove how things are specified by the standard, espcially when the code has UB looking at the assembly can only be misleading – 463035818_is_not_an_ai Jul 03 '21 at 20:27
  • @Top-Master Both compiler in my link resulted to `3`, which at least says it doesn't have to perform increment after the end of the line. – Ranoiaetep Jul 03 '21 at 20:32
  • @Ranoiaetep thanks man! now I can delete my post in peace. Hmm... does UB mean Upper-Bound? (btw imho rn ppl shorten what shouldn't, yes encryption is fun). – Top-Master Jul 03 '21 at 20:33
  • @Top-Master UB means undefined behavior – Ranoiaetep Jul 03 '21 at 20:35
  • @Top-Master [undefined behavior](https://en.cppreference.com/w/cpp/language/ub) and https://stackoverflow.com/questions/367633/what-are-all-the-common-undefined-behaviours-that-a-c-programmer-should-know-a – 463035818_is_not_an_ai Jul 03 '21 at 20:35
  • Has someone power to remove all undefined-behavior from C++ plz? Or at least, ask for this feature somewhere? Most of *undefined-behavior* is only meant to make Compiler-Implementation simpler (with the cost of making developer lives harder). – Top-Master Jul 03 '21 at 20:55
1

The reason here is it doesn't make sense to perform a post-increment to the result that is produced by a post-increment.

Let's first see what exactly a++ does:

int operator++(int)
{
    auto temp = *this;
    *this += 1;
    return temp;
}

So when you perform a++, a would be incremented by 1, and then it returns a temporary value that is equals to what a used to be.

Now imagine if you perform this for a second time, what you are essentially doing is:

int post_increment_twice()
{
    auto temp1 = *this;
    *this += 1;
    auto temp2 = temp1;
    temp1 += 1;
    return temp2;
}

You would notice that the result is exactly the same as post increment once.

  • *this was incremented once
  • then you return the value *this used to be.

  • In fact, it doesn't make sense to perform a post-increment on any temporary values.

Post-increment performs an increment to the value inside the function. However, by passing in a temporary value, you lose the access the incremented object. And returns a value that is equal to the temporary value before it was incremented.


While it is possible to overload a post-increment operator for custom classes to accept temporary values. But with integers, it simply doesn't make sense to accept that, thus it was not allowed.

Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39