mirror of
https://github.com/boostorg/core.git
synced 2025-07-30 04:47:24 +02:00
Propagate noexcept specification in boost::swap.
Mark boost::swap noexcept if the type supports non-throwing swap implementation.
This commit is contained in:
@ -15,6 +15,7 @@
|
|||||||
Users are advised to use [@http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/index.html Boost.TypeTraits]
|
Users are advised to use [@http://www.boost.org/doc/libs/release/libs/type_traits/doc/html/index.html Boost.TypeTraits]
|
||||||
or C++ standard library type traits instead.
|
or C++ standard library type traits instead.
|
||||||
* Marked `boost::ref` member functions and associated methods with `noexcept`.
|
* Marked `boost::ref` member functions and associated methods with `noexcept`.
|
||||||
|
* Marked `boost::swap` function with `noexcept`, depending on whether the type supports a non-throwing swap operation.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
40
doc/swap.qbk
40
doc/swap.qbk
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
[section Header <boost/core/swap.hpp>]
|
[section Header <boost/core/swap.hpp>]
|
||||||
|
|
||||||
`template<class T> void swap(T& left, T& right);`
|
[^template<class T> void swap(T& left, T& right) noexcept(['see below]);]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@ -40,13 +40,14 @@ specialized swap function is available, `std::swap` is used.
|
|||||||
The generic `std::swap` function requires that the elements
|
The generic `std::swap` function requires that the elements
|
||||||
to be swapped are assignable and copy constructible. It is
|
to be swapped are assignable and copy constructible. It is
|
||||||
usually implemented using one copy construction and two
|
usually implemented using one copy construction and two
|
||||||
assignments - this is often both unnecessarily restrictive and
|
assignments (C++11 replaces copy operations with move) - this
|
||||||
unnecessarily slow. In addition, where the generic swap
|
is often both unnecessarily restrictive and unnecessarily slow.
|
||||||
implementation provides only the basic guarantee, specialized
|
In addition, where the generic swap implementation provides
|
||||||
swap functions are often able to provide the no-throw exception
|
only the basic guarantee, specialized swap functions are often
|
||||||
guarantee (and it is considered best practice to do so where
|
able to provide the no-throw exception guarantee (and it is
|
||||||
possible [footnote Scott Meyers, Effective C++ Third Edition,
|
considered best practice to do so where possible[footnote Scott
|
||||||
Item 25: "Consider support for a non-throwing swap"].
|
Meyers, Effective C++ Third Edition, Item 25: "Consider support
|
||||||
|
for a non-throwing swap"].
|
||||||
|
|
||||||
The alternative to using argument dependent lookup in this
|
The alternative to using argument dependent lookup in this
|
||||||
situation is to provide a template specialization of
|
situation is to provide a template specialization of
|
||||||
@ -59,12 +60,12 @@ in their own namespaces.
|
|||||||
`std::swap` originally did not do so, but a request to add an
|
`std::swap` originally did not do so, but a request to add an
|
||||||
overload of `std::swap` for built-in arrays has been accepted
|
overload of `std::swap` for built-in arrays has been accepted
|
||||||
by the C++ Standards Committee[footnote
|
by the C++ Standards Committee[footnote
|
||||||
[@http://open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#809
|
[@http://open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#809
|
||||||
LWG Defect Report 809: std::swap should be overloaded for array
|
LWG Defect Report 809: std::swap should be overloaded for array
|
||||||
types]].
|
types]].
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Exception Safety]
|
[section Exception Safety]
|
||||||
|
|
||||||
`boost::swap` provides the same exception guarantee as the
|
`boost::swap` provides the same exception guarantee as the
|
||||||
@ -73,30 +74,33 @@ of type `T[n]`, where `n > 1` and the underlying swap function
|
|||||||
for `T` provides the strong exception guarantee, `boost::swap`
|
for `T` provides the strong exception guarantee, `boost::swap`
|
||||||
provides only the basic exception guarantee.
|
provides only the basic exception guarantee.
|
||||||
|
|
||||||
|
In C++11 and later, `boost::swap` propagates the same `noexcept`
|
||||||
|
specification as the one specified in the underlying swap function.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Requirements]
|
[section Requirements]
|
||||||
|
|
||||||
Either:
|
Either:
|
||||||
|
|
||||||
* T must be assignable
|
* `T` must be copy assignable (/since C++11:/ move assignable)
|
||||||
* T must be copy constructible
|
* `T` must be copy constructible (/since C++11:/ move constructible)
|
||||||
|
|
||||||
Or:
|
Or:
|
||||||
|
|
||||||
* A function with the signature `swap(T&,T&)` is available via
|
* A function with the signature `swap(T&, T&)` is available via
|
||||||
argument dependent lookup
|
argument dependent lookup
|
||||||
|
|
||||||
Or:
|
Or:
|
||||||
|
|
||||||
* A template specialization of `std::swap` exists for T
|
* A template specialization of `std::swap` exists for `T`
|
||||||
|
|
||||||
Or:
|
Or:
|
||||||
|
|
||||||
* T is a built-in array of swappable elements
|
* `T` is a built-in array of swappable elements
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Portability]
|
[section Portability]
|
||||||
|
|
||||||
Several older compilers do not support argument dependent
|
Several older compilers do not support argument dependent
|
||||||
@ -104,11 +108,11 @@ lookup. On these compilers `boost::swap` will call
|
|||||||
`std::swap`, ignoring any specialized swap functions that
|
`std::swap`, ignoring any specialized swap functions that
|
||||||
could be found as a result of argument dependent lookup.
|
could be found as a result of argument dependent lookup.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Credits]
|
[section Credits]
|
||||||
|
|
||||||
* *Niels Dekker* - for implementing and documenting support for
|
* *Niels Dekker* - for implementing and documenting support for
|
||||||
built-in arrays
|
built-in arrays
|
||||||
* *Joseph Gauterin* - for the initial idea, implementation,
|
* *Joseph Gauterin* - for the initial idea, implementation,
|
||||||
tests, and documentation
|
tests, and documentation
|
||||||
|
@ -13,10 +13,10 @@
|
|||||||
// - swap_impl is put outside the boost namespace, to avoid infinite
|
// - swap_impl is put outside the boost namespace, to avoid infinite
|
||||||
// recursion (causing stack overflow) when swapping objects of a primitive
|
// recursion (causing stack overflow) when swapping objects of a primitive
|
||||||
// type.
|
// type.
|
||||||
// - swap_impl has a using-directive, rather than a using-declaration,
|
// - std::swap is imported with a using-directive, rather than
|
||||||
// because some compilers (including MSVC 7.1, Borland 5.9.3, and
|
// a using-declaration, because some compilers (including MSVC 7.1,
|
||||||
// Intel 8.1) don't do argument-dependent lookup when it has a
|
// Borland 5.9.3, and Intel 8.1) don't do argument-dependent lookup
|
||||||
// using-declaration instead.
|
// when it has a using-declaration instead.
|
||||||
// - boost::swap has two template arguments, instead of one, to
|
// - boost::swap has two template arguments, instead of one, to
|
||||||
// avoid ambiguity when swapping objects of a Boost type that does
|
// avoid ambiguity when swapping objects of a Boost type that does
|
||||||
// not have its own boost::swap overload.
|
// not have its own boost::swap overload.
|
||||||
@ -30,6 +30,13 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <cstddef> // for std::size_t
|
#include <cstddef> // for std::size_t
|
||||||
|
|
||||||
|
#if defined(BOOST_GCC) && (BOOST_GCC < 40700)
|
||||||
|
// gcc 4.6 ICEs on noexcept specifications below
|
||||||
|
#define BOOST_CORE_SWAP_NOEXCEPT_IF(x)
|
||||||
|
#else
|
||||||
|
#define BOOST_CORE_SWAP_NOEXCEPT_IF(x) BOOST_NOEXCEPT_IF(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost_swap_impl
|
namespace boost_swap_impl
|
||||||
{
|
{
|
||||||
// we can't use type_traits here
|
// we can't use type_traits here
|
||||||
@ -37,17 +44,22 @@ namespace boost_swap_impl
|
|||||||
template<class T> struct is_const { enum _vt { value = 0 }; };
|
template<class T> struct is_const { enum _vt { value = 0 }; };
|
||||||
template<class T> struct is_const<T const> { enum _vt { value = 1 }; };
|
template<class T> struct is_const<T const> { enum _vt { value = 1 }; };
|
||||||
|
|
||||||
|
// Use std::swap if argument dependent lookup fails.
|
||||||
|
// We need to have this at namespace scope to be able to use unqualified swap() call
|
||||||
|
// in noexcept specification.
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
BOOST_GPU_ENABLED
|
BOOST_GPU_ENABLED
|
||||||
void swap_impl(T& left, T& right)
|
void swap_impl(T& left, T& right) BOOST_CORE_SWAP_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(swap(left, right)))
|
||||||
{
|
{
|
||||||
using namespace std;//use std::swap if argument dependent lookup fails
|
swap(left, right);
|
||||||
swap(left,right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, std::size_t N>
|
template<class T, std::size_t N>
|
||||||
BOOST_GPU_ENABLED
|
BOOST_GPU_ENABLED
|
||||||
void swap_impl(T (& left)[N], T (& right)[N])
|
void swap_impl(T (& left)[N], T (& right)[N])
|
||||||
|
BOOST_CORE_SWAP_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(::boost_swap_impl::swap_impl(left[0], right[0])))
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < N; ++i)
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
{
|
{
|
||||||
@ -62,9 +74,12 @@ namespace boost
|
|||||||
BOOST_GPU_ENABLED
|
BOOST_GPU_ENABLED
|
||||||
typename enable_if_c< !boost_swap_impl::is_const<T1>::value && !boost_swap_impl::is_const<T2>::value >::type
|
typename enable_if_c< !boost_swap_impl::is_const<T1>::value && !boost_swap_impl::is_const<T2>::value >::type
|
||||||
swap(T1& left, T2& right)
|
swap(T1& left, T2& right)
|
||||||
|
BOOST_CORE_SWAP_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(::boost_swap_impl::swap_impl(left, right)))
|
||||||
{
|
{
|
||||||
::boost_swap_impl::swap_impl(left, right);
|
::boost_swap_impl::swap_impl(left, right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef BOOST_CORE_SWAP_NOEXCEPT_IF
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,6 +13,7 @@ compile swap_lib_header_1.cpp ;
|
|||||||
compile swap_lib_header_2.cpp ;
|
compile swap_lib_header_2.cpp ;
|
||||||
compile swap_mixed_headers_1.cpp ;
|
compile swap_mixed_headers_1.cpp ;
|
||||||
compile swap_mixed_headers_2.cpp ;
|
compile swap_mixed_headers_2.cpp ;
|
||||||
|
compile swap_noexcept.cpp ;
|
||||||
|
|
||||||
compile-fail swap_const_wrapper_fail.cpp ;
|
compile-fail swap_const_wrapper_fail.cpp ;
|
||||||
|
|
||||||
|
42
test/swap/swap_noexcept.cpp
Normal file
42
test/swap/swap_noexcept.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) 2023 Andrey Semashev
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// Tests that boost::swap propagates noexcept specification correctly
|
||||||
|
|
||||||
|
#include <boost/core/swap.hpp>
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_CXX11_STATIC_ASSERT) && \
|
||||||
|
!(defined(BOOST_GCC) && (BOOST_GCC < 40700))
|
||||||
|
|
||||||
|
namespace test_ns {
|
||||||
|
|
||||||
|
struct class_with_noexcept_swap
|
||||||
|
{
|
||||||
|
static class_with_noexcept_swap& instance() noexcept;
|
||||||
|
|
||||||
|
friend void swap(class_with_noexcept_swap&, class_with_noexcept_swap&) noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct class_with_except_swap
|
||||||
|
{
|
||||||
|
static class_with_except_swap& instance() noexcept;
|
||||||
|
|
||||||
|
friend void swap(class_with_except_swap&, class_with_except_swap&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace test_ns
|
||||||
|
|
||||||
|
static_assert(noexcept(boost::swap(test_ns::class_with_noexcept_swap::instance(), test_ns::class_with_noexcept_swap::instance())),
|
||||||
|
"boost::swap for class_with_noexcept_swap should have noexcept specification");
|
||||||
|
static_assert(!noexcept(boost::swap(test_ns::class_with_except_swap::instance(), test_ns::class_with_except_swap::instance())),
|
||||||
|
"boost::swap for class_with_except_swap should not have noexcept specification");
|
||||||
|
|
||||||
|
#endif // !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_CXX11_STATIC_ASSERT) ...
|
Reference in New Issue
Block a user