-1

Reading ES.43: Avoid expressions with undefined order of evaluation, it states that the result of this expression

v[i] = ++i;

is undefined. I'm assuming that's another way to say we got undefined behavior (UB). Reading SO posts on this topic, specifically Why is i = i++ + 1 undefined behavior in C++11? and Undefined behavior and sequence points, I conclude that the expression should be well-defined since:

  1. Value computation of right operand is sequenced before value computation of left operand for assignment operator (N4835, §[expr.ass]/1.)
  2. Side-effect of pre-increment operator is sequenced before value computation of the preincrement (sub)expression (hopefully; don't have source for this)

meaning we do not have any side-effect unsequenced to value computation or another side-effect for the same object.

What am I missing?

Note: My question is intended for C++20. If there is any changes regarding this in previous Standards (up until C++11; so C++11, C++14 and C++17) I would like to know the changes as well. Also, I've noticed a similar post on this Why is i = v[i++] undefined?, but it's about post-increment so I didn't find an answer there.

Nimrod
  • 2,908
  • 9
  • 20
domdrag
  • 541
  • 1
  • 4
  • 13
  • Please be more specific than "intended for C++11 or higher", because behavior regarding sequencing have been changed in later standards. – Some programmer dude Nov 30 '22 at 07:40
  • 3
    This got changed in C++17, your quote from N4835 is C++20 AFAIK. It is UB before C++17, well-defined after. – Quimby Nov 30 '22 at 07:41
  • 8
    I'm not saying the question isn't interesting, but the practical advice is don't ever write code like that. – john Nov 30 '22 at 07:44
  • The question here is whether the preincrement happens before the left hand side. In the newer C++ versions seemingly not. But with the optimization capabilities of a compiler such debatable/misunderstandable code should definitely be avoided. In contrast to leaving out parentheses with operator precedence. – Joop Eggen Nov 30 '22 at 07:48
  • @Someprogrammerdude I've edited the question, hopefully it clears things out. – domdrag Nov 30 '22 at 07:48
  • @Quimby AFAIK, the sequence points terminology was replaced with sequnced before/after terminology in C++11, but I do not know any other changes regarding this after C++11. – domdrag Nov 30 '22 at 07:48
  • Perhaps [this evaluation order and sequencing reference](https://en.cppreference.com/w/cpp/language/eval_order) be helpful? It shows that C++17 have changed some parts, and added quite a few points. – Some programmer dude Nov 30 '22 at 07:55
  • GCC still warns about that, clang does not: https://godbolt.org/z/PdY9Mbzah – mch Nov 30 '22 at 07:57
  • @domdrag Yea, it got replaced but it was never used for `=` definition in the Standard before C++17. – Quimby Nov 30 '22 at 08:02
  • @Quimby Interesting. So what is the rationale for it being UB if they didn't use the sequenced before terminology in C++11 and C++14? Sequence points? – domdrag Nov 30 '22 at 08:05
  • @domdrag I recall it being used somewhere, just not between left and right sides of `=`, feel free to compare C++14,17 standards https://github.com/timsong-cpp/cppwp – Quimby Nov 30 '22 at 08:12

1 Answers1

2

Value computation of right operand is sequenced before value computation of left operand for assignment operator (N4835, §[expr.ass]/1.)

Not only value computation, also side effects. This rule was however added only with C++17.

This rule alone is enough to make your expression well-defined. But even if the side effects weren't sequenced through =, ++i is defined to be identical to i+=1, and [expr.ass]/1 also says that the side effect of (compound) assignment is sequenced before its value computation, so that your second rule is true (even before C++17).

What am I missing?

The core guidelines are not purely about C++17 and later. They are warning you that this may be undefined behavior depending on standard version chosen and because it is likely to be completely silent UB, that is still dangerous. There is practically no good reason to write expressions like this. Simply separating into two statement ++i; v[i] = i; takes barely any longer to write and is much easier to follow, regardless of whether v[i] = ++i; also works.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Interesting. So I guess this means that `i = i++;` is also well-defined in C++17. When you say "This rule was however added only with C++17", do you mean C++17 only or does the same work for C++20 as well? – domdrag Nov 30 '22 at 11:49
  • 1
    @domdrag The rule applies to C++17 and later. It would be very surprising if a guaranteed order of evaluation like this would be made UB by a new version. Yes, `i = i++;` is also well-defined since C++17. – user17732522 Nov 30 '22 at 15:37