Firstly - a[i] = a[i++]
is well-defined since C++17. The sequencing rules were considerably tightened in that revision of the Standard, and the evalution of the right-hand side of an assignment operator is sequenced before the evaluation of the left hand side, meaning that all side-effects of the right-hand side must be complete before evaluation of the left-hand side begins.
So that code is equivalent to a[i+1] = a[i]; ++i;
Since C++17, the <<
operator also has left-right sequencing, i.e. the left operand is sequenced before the right operand.
Now, ++i
is defined as i+=1
and similar considerations as above apply to the evaluation of the compound assignment operator. The ++i
occurs "atomically" we could say.
However, the +
operator is still unsequenced, this is defined by [intro.execution]/17:
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
[...]
If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not
potentially concurrent, the behavior is undefined
Unfortunately this means the behaviour of ++i + a[++i]
is still undefined, because the left operand of +
modifies i
, and the right operand of +
modifies i
, and those operand evaluations are unsequenced relative to each other.
It has previously been proposed to make +
and similar operators be left-right sequenced as well, but apparently this hasn't been accepted into the Standard yet.