From a2b6ba85f3fda0a9e250c8a42709fd7a9aa5ce02 Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Wed, 1 Aug 2018 08:41:32 -0400 Subject: [PATCH] Simplify exception safety in array construct utilities --- .../boost/smart_ptr/allocate_shared_array.hpp | 173 ++++++------------ 1 file changed, 59 insertions(+), 114 deletions(-) diff --git a/include/boost/smart_ptr/allocate_shared_array.hpp b/include/boost/smart_ptr/allocate_shared_array.hpp index 3406881..61beef4 100644 --- a/include/boost/smart_ptr/allocate_shared_array.hpp +++ b/include/boost/smart_ptr/allocate_shared_array.hpp @@ -1,5 +1,5 @@ /* -Copyright 2012-2017 Glen Joseph Fernandes +Copyright 2012-2018 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. @@ -154,33 +154,58 @@ sp_array_destroy(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { } template inline typename sp_enable::value>::type -sp_array_destroy(A&, T* start, std::size_t size) +sp_array_destroy(A&, T* ptr, std::size_t size) { while (size > 0) { - start[--size].~T(); + ptr[--size].~T(); } } #if !defined(BOOST_NO_CXX11_ALLOCATOR) template inline typename sp_enable::type -sp_array_destroy(A& allocator, T* start, std::size_t size) +sp_array_destroy(A& allocator, T* ptr, std::size_t size) { while (size > 0) { - std::allocator_traits::destroy(allocator, start + --size); + std::allocator_traits::destroy(allocator, ptr + --size); } } #endif +template +class sp_destroyer { +public: + sp_destroyer(A& allocator, T* ptr) BOOST_SP_NOEXCEPT + : allocator_(allocator), + ptr_(ptr), + size_(0) { } + + ~sp_destroyer() { + sp_array_destroy(allocator_, ptr_, size_); + } + + std::size_t& size() BOOST_SP_NOEXCEPT { + return size_; + } + +private: + sp_destroyer(const sp_destroyer&); + sp_destroyer& operator=(const sp_destroyer&); + + A& allocator_; + T* ptr_; + std::size_t size_; +}; + template inline typename sp_enable::value && boost::has_trivial_assign::value && boost::has_trivial_destructor::value>::type -sp_array_construct(A&, T* start, std::size_t size) +sp_array_construct(A&, T* ptr, std::size_t size) { for (std::size_t i = 0; i < size; ++i) { - start[i] = T(); + ptr[i] = T(); } } @@ -189,30 +214,11 @@ inline typename sp_enable::value && boost::has_trivial_assign::value && boost::has_trivial_destructor::value>::type -sp_array_construct(A&, T* start, std::size_t size, const T* list, +sp_array_construct(A&, T* ptr, std::size_t size, const T* list, std::size_t count) { for (std::size_t i = 0; i < size; ++i) { - start[i] = list[i % count]; - } -} - -#if !defined(BOOST_NO_EXCEPTIONS) -template -inline typename sp_enable::value && - boost::has_trivial_assign::value && - boost::has_trivial_destructor::value)>::type -sp_array_construct(A& none, T* start, std::size_t size) -{ - std::size_t i = 0; - try { - for (; i < size; ++i) { - ::new(static_cast(start + i)) T(); - } - } catch (...) { - sp_array_destroy(none, start, i); - throw; + ptr[i] = list[i % count]; } } @@ -221,30 +227,13 @@ inline typename sp_enable::value && boost::has_trivial_assign::value && boost::has_trivial_destructor::value)>::type -sp_array_construct(A& none, T* start, std::size_t size, const T* list, - std::size_t count) +sp_array_construct(A& none, T* ptr, std::size_t size) { - std::size_t i = 0; - try { - for (; i < size; ++i) { - ::new(static_cast(start + i)) T(list[i % count]); - } - } catch (...) { - sp_array_destroy(none, start, i); - throw; - } -} -#else -template -inline typename sp_enable::value && - boost::has_trivial_assign::value && - boost::has_trivial_destructor::value)>::type -sp_array_construct(A&, T* start, std::size_t size) -{ - for (std::size_t i = 0; i < size; ++i) { - ::new(static_cast(start + i)) T(); + sp_destroyer hold(none, ptr); + for (std::size_t& i = hold.size(); i < size; ++i) { + ::new(static_cast(ptr + i)) T(); } + hold.size() = 0; } template @@ -252,100 +241,56 @@ inline typename sp_enable::value && boost::has_trivial_assign::value && boost::has_trivial_destructor::value)>::type -sp_array_construct(A&, T* start, std::size_t size, const T* list, +sp_array_construct(A& none, T* ptr, std::size_t size, const T* list, std::size_t count) { - for (std::size_t i = 0; i < size; ++i) { - ::new(static_cast(start + i)) T(list[i % count]); + sp_destroyer hold(none, ptr); + for (std::size_t& i = hold.size(); i < size; ++i) { + ::new(static_cast(ptr + i)) T(list[i % count]); } + hold.size() = 0; } -#endif #if !defined(BOOST_NO_CXX11_ALLOCATOR) -#if !defined(BOOST_NO_EXCEPTIONS) template inline typename sp_enable::type -sp_array_construct(A& allocator, T* start, std::size_t size) +sp_array_construct(A& allocator, T* ptr, std::size_t size) { - std::size_t i = 0; - try { - for (i = 0; i < size; ++i) { - std::allocator_traits::construct(allocator, start + i); - } - } catch (...) { - sp_array_destroy(allocator, start, i); - throw; + sp_destroyer hold(allocator, ptr); + for (std::size_t& i = hold.size(); i < size; ++i) { + std::allocator_traits::construct(allocator, ptr + i); } + hold.size() = 0; } template inline typename sp_enable::type -sp_array_construct(A& allocator, T* start, std::size_t size, const T* list, +sp_array_construct(A& allocator, T* ptr, std::size_t size, const T* list, std::size_t count) { - std::size_t i = 0; - try { - for (i = 0; i < size; ++i) { - std::allocator_traits::construct(allocator, start + i, - list[i % count]); - } - } catch (...) { - sp_array_destroy(allocator, start, i); - throw; - } -} -#else -template -inline typename sp_enable::type -sp_array_construct(A& allocator, T* start, std::size_t size) -{ - for (std::size_t i = 0; i < size; ++i) { - std::allocator_traits::construct(allocator, start + i); - } -} - -template -inline typename sp_enable::type -sp_array_construct(A& allocator, T* start, std::size_t size, const T* list, - std::size_t count) -{ - for (std::size_t i = 0; i < size; ++i) { - std::allocator_traits::construct(allocator, start + i, + sp_destroyer hold(allocator, ptr); + for (std::size_t& i = hold.size(); i < size; ++i) { + std::allocator_traits::construct(allocator, ptr + i, list[i % count]); } + hold.size() = 0; } #endif -#endif template inline typename sp_enable::value>::type sp_array_default(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { } -#if !defined(BOOST_NO_EXCEPTIONS) template inline typename sp_enable::value>::type -sp_array_default(A& none, T* start, std::size_t size) +sp_array_default(A& none, T* ptr, std::size_t size) { - std::size_t i = 0; - try { - for (; i < size; ++i) { - ::new(static_cast(start + i)) T; - } - } catch (...) { - sp_array_destroy(none, start, i); - throw; + sp_destroyer hold(none, ptr); + for (std::size_t& i = hold.size(); i < size; ++i) { + ::new(static_cast(ptr + i)) T; } + hold.size() = 0; } -#else -template -inline typename sp_enable::value>::type -sp_array_default(A&, T* start, std::size_t size) -{ - for (std::size_t i = 0; i < size; ++i) { - ::new(static_cast(start + i)) T; - } -} -#endif template class sp_array_state {