Closed ImplOfAnImpl closed 3 years ago
I've checked that using boost::has_trivial_copy instead of Boost.Move's version does not fix the issue, because TypeTraits uses the same intrinsics as Boost.Move. The alternative is to use the new intrinsics like "__is_trvially_copy_constructible", at least for Clang and GCC. The following commit adapts Boost.Move to use the new intrinsics:
https://github.com/boostorg/move/commit/eb941db76cf8fb24742570f5ab1551b49adb8faa
This should probably go to boost.move, but since the issue affects
boost::container::vector
badly, I'm reporting it here.So I've had this naive wrapper for
std::thread
:I've had a vector of them and it all worked fine until I replaced std::vector with boost::container::vector. In short, the following code freezes when built with GCC (I've tried GCC 5.x, 6.x and 10):
What happens here is that boost.container checks whether the type is trivially copyable and, if so, performs a memcpy instead of the proper call to a ctor or assignment operator. The check is done via type trait classes from boost.move, which rely on certain compiler intrinsics, e.g.has_trivial_copy. Those intrinsics don't always work as expected, e.g. has_trivial_copy returns true for non-copyable types, so boost.move first checks that the type is copyable. But ThreadWrapper's ctor is too generic and it can be selected as a copy ctor with a non const argument. As a result,
boost::move_detail::is_trivially_copy_constructible<ThreadWrapper>::value
becomes true andvector
starts memcpy'ing it. In case of libstdc++ this results injoin()
being called too early.I've also come up with a more synthetic test, which doesn't depend on the flavor of the standard library being used:
Here all counters should be zero but they are not:
P.S. I've solved the problem locally by patching boost/move/detail/type_traits.hpp as follows: