11

Can I use x on both sides of a boolean expression when I post-increment it on the left side?

The line in question is:

 if(x-- > 0 && array[x]) { /* … use x … */ }

Is that defined through the standard? Will array[x] use the new value of x or the old one?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
knittl
  • 246,190
  • 53
  • 318
  • 364
  • 7
    remember to keep your code clean for others to read, even if is well defined it may introduce an issue if somebody later changes or adds to the expression. Just my 2c – AndersK Oct 28 '10 at 15:37
  • 6
    Even if it may be well defined, you should not use such kind code. You may understand it as you write it, but the next peson may not. – codymanix Oct 28 '10 at 15:39
  • this code is not too bad after all. i've seen worse code in the linux kernel :D – knittl Oct 28 '10 at 15:48
  • Please specify the type of `x`. If x is an integer then yes. If it is a class depends on if somebody was stupid enough to define the && operator for the class (against every coding convention known). – Martin York Oct 28 '10 at 18:05
  • @knittl "not too bad after all"-- Poor praise indeed. I wouldn't judge my code against the linux kernel. We don't want to write code that is "not too bad". We want to write code that is simple and obvious, clear and clean. – Rob K Jan 03 '17 at 20:54

2 Answers2

12

It depends.

If && is the usual short-circuiting logical operator, then it's fine because there's a sequence point. array[x] will use the new value.

If && is a user (or library) defined overloaded operator, then there is no short-circuit, and also no guarantee of a sequence point between the evaluation of x-- and the evaluation of array[x]. This looks unlikely given your code, but without context it is not possible to say for sure. I think it's possible, with careful definition of array, to arrange it that way.

This is why it's almost always a bad idea to overload operator&&.

By the way, if ((x > 0) && array[--x]) has a very similar effect (again, assuming no operator overloading shenanigans), and in my opinion is clearer. The difference is whether or not x gets decremented past 0, which you may or may not be relying on.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Since when can you overload `operator&&` at all? – zwol Oct 28 '10 at 15:45
  • it's the boolean operator && and it's not overloaded – knittl Oct 28 '10 at 15:45
  • @Steve: Even if && were overloaded it would still be defined behavior, no? – Armen Tsirunyan Oct 28 '10 at 15:46
  • @Zack: certainly since the C++ standard was finalized, I don't know about before that. – Steve Jessop Oct 28 '10 at 15:49
  • @Armen: I think not, although I'm not entirely sure in this case. My thinking is that suppose `x` is an integer type, and `array` is an array of some type T for which a `bool operator&&(bool, const T&)` overload exists. Then there's no sequence point between the evaluation of `x--` and the evaluation of `array[x]` (because none of that is overloaded), hence undefined behavior. I may have missed something which makes it defined, though - I'm a C++ user rather than a C++ compiler-writer, so if I'm going to err I try to err on the side of assuming something is undefined until proven otherwise. – Steve Jessop Oct 28 '10 at 15:50
  • @Armen: if both x is int and array is an array then it's impossible to overload for them. – Armen Tsirunyan Oct 28 '10 at 16:14
  • @Armen: it doesn't really matter whether anything is overloaded for `x` or for `array`. I mention it only because if they're not overloaded, then we can be sure there are no sequence points other than for the `&&`, which simplifies things a bit. The issue is whether anything is overloaded for `array[x]`. – Steve Jessop Oct 28 '10 at 16:26
11

Yes, it is well defined. && introduces a sequence point.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 1
    Huh, I have the feeling that you or others are using some feed like Twitter in order to answer so darned fast. When I first see a question it's generally already answered... ? – Cheers and hth. - Alf Oct 28 '10 at 15:37
  • @Alf P. Steinbach, click the "questions" link once in a second – Harmen Oct 28 '10 at 15:38
  • @Alf: When I saw this question it was unanswered and so I answered it. The trick is : Refresh the "New questions" page at least once in 10 seconds. `;-)` – Prasoon Saurav Oct 28 '10 at 15:40
  • 1
    so, `array[x]` uses the old or the new value? – knittl Oct 28 '10 at 15:49
  • hmm I thought it would get the old value... oh well – BЈовић Oct 28 '10 at 18:36
  • @VJovic the built-in && operator is short-circuiting. This means that the second half of the expression is *only* evaluated after the first half has also succeeded. That's why "if (X != NULL && X->foo == 2)" is valid. – Kaz Dragon Feb 09 '12 at 09:34
  • @KazDragon I wanted to say that I didn't know that the `&&` introduces a sequence point. Anyway I find that code quite awful. Have 2 ifs is more clear and easier to debug. *Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.* This holds specially if someone else has to debug your code, because not all people have the same level of knowledge and experience. – BЈовић Feb 09 '12 at 10:35
  • @VJovic Preaching to the choir, here. I'd say what I wrote is actually quite idiomatic: testing the LHS, using the result in the RHS is a very common pattern. Actually modifying the LHS in the process, however, requires scrutiny and hits your complaint. – Kaz Dragon Feb 09 '12 at 16:34