https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124121
--- Comment #16 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Placement new will only create the lifetime of a T at a particular location
(which happens to be within the storage for an array in the union).
But performing pointer arithmetic like &_M_elems[0] + 2 is UB unless there's an
array there, and we never created an array. We just have a collection of
unrelated T objects, floating in memory. They're not members of the same array,
so we can't use pointer arithmetic to get from one to the next (so can't
iterate over the container).
The pointer arithmetic works for std::vector because heap memory (created by
malloc, or operator new) has magic properties that "implicitly create objects".
There's no equivalent magic for an uninitialized union { T elems[N]; } in a
stack variable.
So the point of the start_lifetime_as_array call is to create an array "around"
the individual T objects, like a frame to hold them in. Because the standard
requires it.
If GCC (and Clang, when it uses out headers) don't actually care about that
rule in the standard, then we can remove the start_lifetime_as_array call.