Subject: [Boost-bugs] [Boost C++ Libraries] #13487: Error detecting is_nothrow_move_constructible & is_nothrow_move_assignable
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2018-03-19 10:10:30
#13487: Error detecting is_nothrow_move_constructible & is_nothrow_move_assignable
-----------------------------------------------+---------------------------
Reporter: Andrey Glebov <andrey458641387@â¦> | Owner: Ion Gaztañaga
Type: Bugs | Status: new
Milestone: To Be Determined | Component: move
Version: Boost Development Trunk | Severity: Problem
Keywords: move noexcept nothrow |
-----------------------------------------------+---------------------------
The current type trait implementation of Boost.Move doesn't detect nothrow
move construction or assignment.
While `boost/move/detail/type_traits.hpp` defines many macros such as
`BOOST_MOVE_HAS_NOTHROW_COPY`, it never defines
`BOOST_MOVE_HAS_NOTHROW_MOVE` or `BOOST_MOVE_HAS_NOTHROW_MOVE_ASSIGN` for
any compiler.
As a result, `boost::move:detail::is_nothrow_move_constructible` and
`is_nothrow_move_assignable` fallback to
`boost::move_detail::is_pod<T>::value` which is incorrect for any non-POD
type.
In my particular instance the result is that `boost::circular_buffer`
chooses copy instead of move in `boost::move_if_noexcept()` for
`std::weak_ptr` (which is nothrow move constructible and assignable),
which in turn results in >10x worse performance of functions such as
`boost::circular_buffer::erase()` in some conditions.
It is possible to work around this by manually specializing
`boost::has_nothrow_move<std::weak_ptr>`, but this is not a practical
workaround.
Another workaround would be to define the trait macros via compiler
switches but this is clearly not the intended
behavior as all other macros are defined in the header, and it might not
be practical as some helper traits may need to be defined too (see
`libstdc++` implementation below).
I propose fixing this issue by defining `BOOST_MOVE_HAS_NOTHROW_MOVE` and
`BOOST_MOVE_HAS_NOTHROW_MOVE_ASSIGN` for all compilers that support move
semantics.
`libstdc++` seems to have the most correct and portable way of doing this
- without using compiler intrinsics:
{{{
#!c++
template<typename _Tp, typename... _Args>
struct __is_nt_constructible_impl
: public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))>
{ };
template<typename _Tp, typename _Arg>
struct __is_nt_constructible_impl<_Tp, _Arg>
: public integral_constant<bool,
noexcept(static_cast<_Tp>(declval<_Arg>()))>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nothrow_move_constructible_impl;
template<typename _Tp>
struct __is_nothrow_move_constructible_impl<_Tp, false>
: public false_type { };
template<typename _Tp>
struct __is_nothrow_move_constructible_impl<_Tp, true>
: public is_nothrow_constructible<_Tp, _Tp&&>
{ };
template<typename _Tp, typename _Up>
struct __is_nt_assignable_impl
: public integral_constant<bool, noexcept(declval<_Tp>() =
declval<_Up>())>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nt_move_assignable_impl;
template<typename _Tp>
struct __is_nt_move_assignable_impl<_Tp, false>
: public false_type { };
template<typename _Tp>
struct __is_nt_move_assignable_impl<_Tp, true>
: public is_nothrow_assignable<_Tp&, _Tp&&>
{ };
}}}
Visual Studio 14.0's implementation uses the intrinsics
`__is_nothrow_constructible(T, Args...)` and `__is_nothrow_assignable(To,
From)` that are passed an rvalue-reference as the second argument to
detect move operations. Sadly, I can't seem to find any documentation on
these intrinsics so it might be better to stick to pure C++ for all
compilers (or maybe i'm just not looking in the right places).
It might also be a good idea to replace the fallback to
`boost::move_detail::is_pod<T>` with more specific and inclusive
`is_trivially_copy_constructible<T>`, `is_trivially_copy_assignable<T>`
type traits.
-- Ticket URL: <https://svn.boost.org/trac10/ticket/13487> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2018-03-19 10:17:53 UTC