Hello,this small patch feels safe: we are moving an existing object to an uninitialized location so the 2 locations can't overlap. And it helps with std::vector<std::unique_ptr<int>> where it lets the compiler get rid of the branches "if(...) delete ..." when moving elements around, for instance in reserve(). We don't get a call to memmove yet (ldist may be confused by clobbers, I'll investigate and report that later), but the code gets much smaller at -O2, and we vectorize at -O3.
Similarly, I think the call to memmove in __relocate_a_1 could probably be memcpy (I don't remember why I chose memmove), but that seems less important and I don't want to mix it with this patch.
Bootstrap+regtest on x86_64-pc-linux-gnu. 2019-04-29 Marc Glisse <marc.gli...@inria.fr> PR libstdc++/87106 * include/bits/stl_uninitialized.h (__relocate_object_a): Mark the arguments with __restrict. -- Marc Glisse
Index: libstdc++-v3/include/bits/stl_uninitialized.h =================================================================== --- libstdc++-v3/include/bits/stl_uninitialized.h (revision 270586) +++ libstdc++-v3/include/bits/stl_uninitialized.h (working copy) @@ -877,21 +877,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __res = std::__uninitialized_copy_n_pair (_GLIBCXX_MAKE_MOVE_ITERATOR(__first), __count, __result); return {__res.first.base(), __res.second}; } #endif // C++17 #if __cplusplus >= 201103L template<typename _Tp, typename _Up, typename _Allocator> inline void - __relocate_object_a(_Tp* __dest, _Up* __orig, _Allocator& __alloc) + __relocate_object_a(_Tp* __restrict __dest, _Up* __restrict __orig, + _Allocator& __alloc) noexcept(noexcept(std::allocator_traits<_Allocator>::construct(__alloc, __dest, std::move(*__orig))) && noexcept(std::allocator_traits<_Allocator>::destroy( __alloc, std::__addressof(*__orig)))) { typedef std::allocator_traits<_Allocator> __traits; __traits::construct(__alloc, __dest, std::move(*__orig)); __traits::destroy(__alloc, std::__addressof(*__orig)); }