https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87106
--- Comment #25 from Jonathan Wakely <redi at gcc dot gnu.org> --- I think that's the answer, yes (although I haven't refreshed my memory of the issues completely). A call to memmove does not begin the lifetime of any objects at the destination address. For types that are trivially-copyable but not trivial we could consider doing a first pass over the range to default-initialize the destination objects, then do the memmove to overwrite them with the desired values. In theory, the optimizer would realize the default-initializations are dead stores and completely remove that first loop (but only after the semantic checks have concluded that we are obeying the languages rules and have no undefined behaviour). So change the bitwise_relocatable condition to is_trivially_copyable && is_default_constructible and make __relocate_a_1 do something like this (completely untested, typing as I think about it): template<typename _Tp, typename = void> struct __is_bitwise_relocatable : __and_<is_trivially_copyable<_Tp>, is_default_constructible<_Tp>> { }; template <typename _Tp, typename _Up> inline __enable_if_t<std::__is_bitwise_relocatable<_Tp>::value, _Tp*> __relocate_a_1(_Tp* __first, _Tp* __last, _Tp* __result, allocator<_Up>& a) noexcept { ptrdiff_t __count = __last - __first; if (__count > 0) { if constexpr (!is_trivial_v<T>) { #ifdef __OPTIMIZE__ // begin lifetime of destination objects std::__uninitialized_default_novalue_n(result, result + count); #else // can't do bitwise relocation today for (ptrdiff_t i = 0; i < count; ++i) __relocate_object_a(result + i, first + i, a); return result + count; #endif } __builtin_memmove(__result, __first, __count * sizeof(_Tp)); } return __result + __count; }