Afaik w C++03 to UB, w C++11,14,17 nie. Zedytuję z cytatami.
C++03: UB
Istotne są:
ISO/IEC 14882:2003 §1.9 [intro.execution]/7 napisał(a)
Accessing an object designated by avolatilelvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are allside effects, which are changes in the state of the execution environment. Evaluation of an expression might produce side effects. At certain specified points in the execution sequence calledsequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.
oraz:
ISO/IEC 14882:2003 §5 [expr]/4 napisał(a)
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.
operator=
nie wprowadza nowego sequence pointa, więc dwukrotny zapis do tej samej zmiennej to UB.
C++11 (i 14): UB, z innego powodu
n3337 §1.9 [intro.execution]/15 napisał(a)
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.
Sequence points zostały zastąpione sequenced after i sequenced before.
n3337 §5.17 [expr.ass] napisał(a)
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
czyli dla i = i = 42
, co jest równoznaczne z zapisem i = (i = 42)
, wyrażenie i = (i = 42)
zostanie wykonane dopiero po zakończeniu obliczania i
i (i = 42)
. Jednak obczenia i
i (i = 42)
są wzajemnie unsequenced. co jednak nie ma się nijak do zacytowanego wyżej punktu standardu, bo tylko jedno z nich ma side-effect.
Ponieważ jedno ma side-effect a drugie to value computation jest to UB.
C++17: well-defined
n4606 §5.18 [expr.ass]/1 napisał(a)
The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand.
Operandy są explicite obliczane w zdefiniowanej kolejności.
Dodatkowo, od C++17 te same zasady obowiązują przeładowane operatory: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf