int arr[2];
int b = arr[2];
According to [expr.sub#1]
The expression E1[E2] is identical (by definition) to *((E1)+(E2)), except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise.
Where (E1)+(E2)
is determined by [expr.add#4.2]
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
- [...]
- Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]), the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i + j of x if 0 ≤ i + j ≤ n and the expression P - J points to the (possibly-hypothetical) array element i - j of x if 0 ≤ i - j ≤ n
- Otherwise, the behavior is undefined.
In this example, arr + 2
points to the hypothetical array element and there is no UB here. The result of *(arr+2)
is a glvalue that refers to the object pointed to by arr + 2
. In the current standard, there is no normative rule that explicitly says indirection of the pointer would result in UB, as well as [basic.life]. Hence, I think there are two interpretations for this example. One is that there is an actual object of type int created in that storage, in this case, int b = arr[2];
is well-defined. The other interpretation is that there's is no object or an object of another type in that storage, according to [basic.lval#11]
If a program attempts to access the stored value of an object through a glvalue whose type is not similar to one of the following types the behavior is undefined:
- the dynamic type of the object,
- a type that is the signed or unsigned type corresponding to the dynamic type of the object, or
- [...]
In this case, the example is judged to be UB. So, I wonder that Is this example definitely UB or the same as what I analyzed(namely, an unspecified case)?