もちろん、それは明確に定義されています。
割り当てがいつp=arr行われるかは関係ありません。評価しているのではなく、に格納されているポインタ値であるp[0]の結果を添え字で示しています。まだ保存されているかどうかは値を変更せず、値はまだ変更されているかどうかに関係なくわかります。(p=arr)pp
同様に、では*--p、未定義の動作はありません。シーケンスポイント間で、少なくとも1回の書き込みを含め、同じ変数に2回アクセスした場合にのみ、未定義の動作が発生します。ただしp、の一部として、一度だけアクセスされます--p。再度読み取られることはありません(*p)。逆参照演算子が適用され、その結果に--p明確に定義されたポインター値が適用されます。
さて、これは未定義の動作になります:
void* a;
void* p = &a;
reinterpret_cast<void**>(p = &p)[0] = 0;
のように
int *pi = new int[5];
int i = **&++pi;
事前インクリメントの結果は、書き込みで順序付けられていない読み取りではないことは明らかです。なぜなら、競合があると主張することは++p、右辺値として使用できないことを主張することであり、その場合、シーケンスポイント間でスタンドアロンである必要があります。代わりにポストインクリメントを使用できます。言語でプリインクリメントとポストインクリメントの両方を使用することに利点はありません。