Consider the following scenario:
std::array<int, 8> a;
auto p = reinterpret_cast<int(*)[8]>(a.data());
(*p)[0] = 42;
Is this undefined behavior? I think it is.
a.data()
returns aint*
, which is not the same asint(*)[8]
The type aliasing rules on cppreference seem to suggest that the
reinterpret_cast
is not validAs a programmer, I know that the memory location pointed by
a.data()
is an array of8
int
objects
Is there any rule I am missing that makes this reinterpret_cast
valid?
An array object and its first element are not pointer-interconvertible*, so the result of the
reinterpret_cast
is a pointer of type "pointer to array of 8int
" whose value is "pointer toa[0]
"1.In other words, despite the type, it does not actually point to any array object.The code then applies the array-to-pointer conversion to the lvalue that resulted from dereferencing such a pointer (as a part of the indexing expression
(*p)[0]
)2. That conversion's behavior is only specified when the lvalue actually refers to an array object3. Since the lvalue in this case does not, the behavior is undefined by omission4.*If the question is "why is an array object and its first element not pointer-interconvertible?", it has already been asked: Pointer interconvertibility vs having the same address.
1See [expr.reinterpret.cast]/7, [conv.ptr]/2, [expr.static.cast]/13 and [basic.compound]/4.
2See [basic.lval]/6, [expr.sub] and [expr.add].
3[conv.array]: "The result is a pointer to the first element of the array."
4[defns.undefined]: undefined behavior is "behavior for which this document imposes no requirements", including "when this document omits any explicit definition of behavior".
Yes the behaviour is undefined.
int*
(the return type ofa.data()
) is a different type fromint(*)[8]
, so you are breaking strict aliasing rules.Naturally though (and this is more for the benefit of future readers),
is perfectly valid, as is the ensuing expression
p + n
where the integral typen
is between 0 and 8 inclusive.