diff mbox series

[1/3] libstdc++: Use RAII in <bits/stl_uninitialized.h>

Message ID 20240627105217.116315-1-jwakely@redhat.com
State New
Headers show
Series [1/3] libstdc++: Use RAII in <bits/stl_uninitialized.h> | expand

Commit Message

Jonathan Wakely June 27, 2024, 10:39 a.m. UTC
This refactoring to use RAII doesn't seem to make any difference in
benchmarks, although the generated code for some std::vector operations
seems to be slightly larger. Maybe it will be faster (or slower) in some
cases I didn't test?

I think I like the change anyway - any other opinions on whether it's an
improvement?

Tested x86_64-linux.

-- >8 --

This adds an _UninitDestroyGuard class template, similar to
ranges::_DestroyGuard used in <bits/ranges_uninitialized.h>. This allows
us to remove all the try-catch blocks and rethrows, because any required
cleanup gets done in the guard destructor.

libstdc++-v3/ChangeLog:

	* include/bits/stl_uninitialized.h (_UninitDestroyGuard): New
	class template and partial specialization.
	(__do_uninit_copy, __do_uninit_fill, __do_uninit_fill_n)
	(__uninitialized_copy_a, __uninitialized_fill_a)
	(__uninitialized_fill_n_a, __uninitialized_copy_move)
	(__uninitialized_move_copy, __uninitialized_fill_move)
	(__uninitialized_move_fill, __uninitialized_default_1)
	(__uninitialized_default_n_a, __uninitialized_default_novalue_1)
	(__uninitialized_default_novalue_n_1, __uninitialized_copy_n)
	(__uninitialized_copy_n_pair): Use it.
---
 libstdc++-v3/include/bits/stl_uninitialized.h | 365 ++++++++----------
 1 file changed, 156 insertions(+), 209 deletions(-)

Comments

Jonathan Wakely July 3, 2024, 3:32 p.m. UTC | #1
On Thu, 27 Jun 2024 at 11:52, Jonathan Wakely wrote:
>
> This refactoring to use RAII doesn't seem to make any difference in
> benchmarks, although the generated code for some std::vector operations
> seems to be slightly larger. Maybe it will be faster (or slower) in some
> cases I didn't test?
>
> I think I like the change anyway - any other opinions on whether it's an
> improvement?

Any thoughts before I push this? Better? Worse? Needs more cowbell?


> Tested x86_64-linux.
>
> -- >8 --
>
> This adds an _UninitDestroyGuard class template, similar to
> ranges::_DestroyGuard used in <bits/ranges_uninitialized.h>. This allows
> us to remove all the try-catch blocks and rethrows, because any required
> cleanup gets done in the guard destructor.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/stl_uninitialized.h (_UninitDestroyGuard): New
>         class template and partial specialization.
>         (__do_uninit_copy, __do_uninit_fill, __do_uninit_fill_n)
>         (__uninitialized_copy_a, __uninitialized_fill_a)
>         (__uninitialized_fill_n_a, __uninitialized_copy_move)
>         (__uninitialized_move_copy, __uninitialized_fill_move)
>         (__uninitialized_move_fill, __uninitialized_default_1)
>         (__uninitialized_default_n_a, __uninitialized_default_novalue_1)
>         (__uninitialized_default_novalue_n_1, __uninitialized_copy_n)
>         (__uninitialized_copy_n_pair): Use it.
> ---
>  libstdc++-v3/include/bits/stl_uninitialized.h | 365 ++++++++----------
>  1 file changed, 156 insertions(+), 209 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h
> index 3c405d8fbe8..a9965f26269 100644
> --- a/libstdc++-v3/include/bits/stl_uninitialized.h
> +++ b/libstdc++-v3/include/bits/stl_uninitialized.h
> @@ -107,24 +107,70 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      __is_trivial(T) && __is_assignable(T&, U)
>  #endif
>
> +  template<typename _ForwardIterator, typename _Alloc = void>
> +    struct _UninitDestroyGuard
> +    {
> +      _GLIBCXX20_CONSTEXPR
> +      explicit
> +      _UninitDestroyGuard(_ForwardIterator& __first, _Alloc& __a)
> +      : _M_first(__first), _M_cur(__builtin_addressof(__first)), _M_alloc(__a)
> +      { }
> +
> +      _GLIBCXX20_CONSTEXPR
> +      ~_UninitDestroyGuard()
> +      {
> +       if (__builtin_expect(_M_cur != 0, 0))
> +         std::_Destroy(_M_first, *_M_cur, _M_alloc);
> +      }
> +
> +      _GLIBCXX20_CONSTEXPR
> +      void release() { _M_cur = 0; }
> +
> +    private:
> +      _ForwardIterator const _M_first;
> +      _ForwardIterator* _M_cur;
> +      _Alloc& _M_alloc;
> +
> +      _UninitDestroyGuard(const _UninitDestroyGuard&);
> +    };
> +
> +  template<typename _ForwardIterator>
> +    struct _UninitDestroyGuard<_ForwardIterator, void>
> +    {
> +      _GLIBCXX20_CONSTEXPR
> +      explicit
> +      _UninitDestroyGuard(_ForwardIterator& __first)
> +      : _M_first(__first), _M_cur(__builtin_addressof(__first))
> +      { }
> +
> +      _GLIBCXX20_CONSTEXPR
> +      ~_UninitDestroyGuard()
> +      {
> +       if (__builtin_expect(_M_cur != 0, 0))
> +         std::_Destroy(_M_first, *_M_cur);
> +      }
> +
> +      _GLIBCXX20_CONSTEXPR
> +      void release() { _M_cur = 0; }
> +
> +      _ForwardIterator const _M_first;
> +      _ForwardIterator* _M_cur;
> +
> +    private:
> +      _UninitDestroyGuard(const _UninitDestroyGuard&);
> +    };
> +
>    template<typename _InputIterator, typename _ForwardIterator>
>      _GLIBCXX20_CONSTEXPR
>      _ForwardIterator
>      __do_uninit_copy(_InputIterator __first, _InputIterator __last,
>                      _ForwardIterator __result)
>      {
> -      _ForwardIterator __cur = __result;
> -      __try
> -       {
> -         for (; __first != __last; ++__first, (void)++__cur)
> -           std::_Construct(std::__addressof(*__cur), *__first);
> -         return __cur;
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__result, __cur);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator> __guard(__result);
> +      for (; __first != __last; ++__first, (void)++__result)
> +       std::_Construct(std::__addressof(*__result), *__first);
> +      __guard.release();
> +      return __result;
>      }
>
>    template<bool _TrivialValueTypes>
> @@ -192,17 +238,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      __do_uninit_fill(_ForwardIterator __first, _ForwardIterator __last,
>                      const _Tp& __x)
>      {
> -      _ForwardIterator __cur = __first;
> -      __try
> -       {
> -         for (; __cur != __last; ++__cur)
> -           std::_Construct(std::__addressof(*__cur), __x);
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__first, __cur);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator> __guard(__first);
> +      for (; __first != __last; ++__first)
> +       std::_Construct(std::__addressof(*__first), __x);
> +      __guard.release();
>      }
>
>    template<bool _TrivialValueType>
> @@ -260,18 +299,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      _ForwardIterator
>      __do_uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
>      {
> -      _ForwardIterator __cur = __first;
> -      __try
> -       {
> -         for (; __n > 0; --__n, (void) ++__cur)
> -           std::_Construct(std::__addressof(*__cur), __x);
> -         return __cur;
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__first, __cur);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator> __guard(__first);
> +      for (; __n > 0; --__n, (void) ++__first)
> +       std::_Construct(std::__addressof(*__first), __x);
> +      __guard.release();
> +      return __first;
>      }
>
>    template<bool _TrivialValueType>
> @@ -344,19 +376,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      __uninitialized_copy_a(_InputIterator __first, _InputIterator __last,
>                            _ForwardIterator __result, _Allocator& __alloc)
>      {
> -      _ForwardIterator __cur = __result;
> -      __try
> -       {
> -         typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> -         for (; __first != __last; ++__first, (void)++__cur)
> -           __traits::construct(__alloc, std::__addressof(*__cur), *__first);
> -         return __cur;
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__result, __cur, __alloc);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator>
> +       __guard(__result, __alloc);
> +
> +      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> +      for (; __first != __last; ++__first, (void)++__result)
> +       __traits::construct(__alloc, std::__addressof(*__result), *__first);
> +      __guard.release();
> +      return __result;
>      }
>
>  #if _GLIBCXX_HOSTED
> @@ -406,18 +433,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      __uninitialized_fill_a(_ForwardIterator __first, _ForwardIterator __last,
>                            const _Tp& __x, _Allocator& __alloc)
>      {
> -      _ForwardIterator __cur = __first;
> -      __try
> -       {
> -         typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> -         for (; __cur != __last; ++__cur)
> -           __traits::construct(__alloc, std::__addressof(*__cur), __x);
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__first, __cur, __alloc);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator>
> +       __guard(__first, __alloc);
> +
> +      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> +      for (; __first != __last; ++__first)
> +       __traits::construct(__alloc, std::__addressof(*__first), __x);
> +
> +      __guard.release();
>      }
>
>  #if _GLIBCXX_HOSTED
> @@ -442,19 +465,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n,
>                              const _Tp& __x, _Allocator& __alloc)
>      {
> -      _ForwardIterator __cur = __first;
> -      __try
> -       {
> -         typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> -         for (; __n > 0; --__n, (void) ++__cur)
> -           __traits::construct(__alloc, std::__addressof(*__cur), __x);
> -         return __cur;
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__first, __cur, __alloc);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator>
> +       __guard(__first, __alloc);
> +      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> +      for (; __n > 0; --__n, (void) ++__first)
> +       __traits::construct(__alloc, std::__addressof(*__first), __x);
> +      __guard.release();
> +      return __first;
>      }
>
>  #if _GLIBCXX_HOSTED
> @@ -493,17 +510,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>                               _Allocator& __alloc)
>      {
>        _ForwardIterator __mid = std::__uninitialized_copy_a(__first1, __last1,
> -                                                          __result,
> -                                                          __alloc);
> -      __try
> -       {
> -         return std::__uninitialized_move_a(__first2, __last2, __mid, __alloc);
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__result, __mid, __alloc);
> -         __throw_exception_again;
> -       }
> +                                                          __result, __alloc);
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__result,
> +                                                               __alloc);
> +      __result = __mid; // Everything up to __mid is now guarded.
> +      __result = std::__uninitialized_move_a(__first2, __last2, __mid, __alloc);
> +      __guard.release();
> +      return __result;
>      }
>
>    // __uninitialized_move_copy
> @@ -521,17 +534,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>                               _Allocator& __alloc)
>      {
>        _ForwardIterator __mid = std::__uninitialized_move_a(__first1, __last1,
> -                                                          __result,
> -                                                          __alloc);
> -      __try
> -       {
> -         return std::__uninitialized_copy_a(__first2, __last2, __mid, __alloc);
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__result, __mid, __alloc);
> -         __throw_exception_again;
> -       }
> +                                                          __result, __alloc);
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__result,
> +                                                               __alloc);
> +      __result = __mid; // Everything up to __mid is now guarded.
> +      __result = std::__uninitialized_copy_a(__first2, __last2, __mid, __alloc);
> +      __guard.release();
>      }
>
>    // __uninitialized_fill_move
> @@ -545,15 +553,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>                               _InputIterator __last, _Allocator& __alloc)
>      {
>        std::__uninitialized_fill_a(__result, __mid, __x, __alloc);
> -      __try
> -       {
> -         return std::__uninitialized_move_a(__first, __last, __mid, __alloc);
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__result, __mid, __alloc);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__result,
> +                                                               __alloc);
> +      __result = __mid; // Everything up to __mid is now guarded.
> +      __result = std::__uninitialized_move_a(__first, __last, __mid, __alloc);
> +      __guard.release();
> +      return __result;
>      }
>
>    // __uninitialized_move_fill
> @@ -570,15 +575,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        _ForwardIterator __mid2 = std::__uninitialized_move_a(__first1, __last1,
>                                                             __first2,
>                                                             __alloc);
> -      __try
> -       {
> -         std::__uninitialized_fill_a(__mid2, __last2, __x, __alloc);
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__first2, __mid2, __alloc);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__first2,
> +                                                               __alloc);
> +      __first2 = __mid2; // Everything up to __mid2 is now guarded.
> +      std::__uninitialized_fill_a(__mid2, __last2, __x, __alloc);
> +      __guard.release();
>      }
>
>    /// @endcond
> @@ -596,17 +597,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>          static void
>          __uninit_default(_ForwardIterator __first, _ForwardIterator __last)
>          {
> -         _ForwardIterator __cur = __first;
> -         __try
> -           {
> -             for (; __cur != __last; ++__cur)
> -               std::_Construct(std::__addressof(*__cur));
> -           }
> -         __catch(...)
> -           {
> -             std::_Destroy(__first, __cur);
> -             __throw_exception_again;
> -           }
> +         _UninitDestroyGuard<_ForwardIterator> __guard(__first);
> +         for (; __first != __last; ++__first)
> +           std::_Construct(std::__addressof(*__first));
> +         __guard.release();
>         }
>      };
>
> @@ -636,18 +630,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>          static _ForwardIterator
>          __uninit_default_n(_ForwardIterator __first, _Size __n)
>          {
> -         _ForwardIterator __cur = __first;
> -         __try
> -           {
> -             for (; __n > 0; --__n, (void) ++__cur)
> -               std::_Construct(std::__addressof(*__cur));
> -             return __cur;
> -           }
> -         __catch(...)
> -           {
> -             std::_Destroy(__first, __cur);
> -             __throw_exception_again;
> -           }
> +         _UninitDestroyGuard<_ForwardIterator> __guard(__first);
> +         for (; __n > 0; --__n, (void) ++__first)
> +           std::_Construct(std::__addressof(*__first));
> +         __guard.release();
> +         return __first;
>         }
>      };
>
> @@ -722,18 +709,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>                               _ForwardIterator __last,
>                               _Allocator& __alloc)
>      {
> -      _ForwardIterator __cur = __first;
> -      __try
> -       {
> -         typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> -         for (; __cur != __last; ++__cur)
> -           __traits::construct(__alloc, std::__addressof(*__cur));
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__first, __cur, __alloc);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__first,
> +                                                               __alloc);
> +      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> +      for (; __first != __last; ++__first)
> +       __traits::construct(__alloc, std::__addressof(*__first));
> +      __guard.release();
>      }
>
>  #if _GLIBCXX_HOSTED
> @@ -753,19 +734,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      __uninitialized_default_n_a(_ForwardIterator __first, _Size __n,
>                                 _Allocator& __alloc)
>      {
> -      _ForwardIterator __cur = __first;
> -      __try
> -       {
> -         typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> -         for (; __n > 0; --__n, (void) ++__cur)
> -           __traits::construct(__alloc, std::__addressof(*__cur));
> -         return __cur;
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__first, __cur, __alloc);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__first,
> +                                                               __alloc);
> +      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
> +      for (; __n > 0; --__n, (void) ++__first)
> +       __traits::construct(__alloc, std::__addressof(*__first));
> +      __guard.release();
> +      return __first;
>      }
>
>  #if _GLIBCXX_HOSTED
> @@ -787,17 +762,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         __uninit_default_novalue(_ForwardIterator __first,
>                                  _ForwardIterator __last)
>         {
> -         _ForwardIterator __cur = __first;
> -         __try
> -           {
> -             for (; __cur != __last; ++__cur)
> -               std::_Construct_novalue(std::__addressof(*__cur));
> -           }
> -         __catch(...)
> -           {
> -             std::_Destroy(__first, __cur);
> -             __throw_exception_again;
> -           }
> +         _UninitDestroyGuard<_ForwardIterator> __guard(__first);
> +         for (; __first != __last; ++__first)
> +           std::_Construct_novalue(std::__addressof(*__first));
> +         __guard.release();
>         }
>      };
>
> @@ -818,18 +786,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         static _ForwardIterator
>         __uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
>         {
> -         _ForwardIterator __cur = __first;
> -         __try
> -           {
> -             for (; __n > 0; --__n, (void) ++__cur)
> -               std::_Construct_novalue(std::__addressof(*__cur));
> -             return __cur;
> -           }
> -         __catch(...)
> -           {
> -             std::_Destroy(__first, __cur);
> -             __throw_exception_again;
> -           }
> +         _UninitDestroyGuard<_ForwardIterator> __guard(__first);
> +         for (; __n > 0; --__n, (void) ++__first)
> +           std::_Construct_novalue(std::__addressof(*__first));
> +         __guard.release();
> +         return __first;
>         }
>      };
>
> @@ -877,18 +838,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      __uninitialized_copy_n(_InputIterator __first, _Size __n,
>                            _ForwardIterator __result, input_iterator_tag)
>      {
> -      _ForwardIterator __cur = __result;
> -      __try
> -       {
> -         for (; __n > 0; --__n, (void) ++__first, ++__cur)
> -           std::_Construct(std::__addressof(*__cur), *__first);
> -         return __cur;
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__result, __cur);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator> __guard(__result);
> +      for (; __n > 0; --__n, (void) ++__first, ++__result)
> +       std::_Construct(std::__addressof(*__result), *__first);
> +      __guard.release();
> +      return __result;
>      }
>
>    template<typename _RandomAccessIterator, typename _Size,
> @@ -903,20 +857,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>            typename _ForwardIterator>
>      pair<_InputIterator, _ForwardIterator>
>      __uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
> -                          _ForwardIterator __result, input_iterator_tag)
> +                               _ForwardIterator __result, input_iterator_tag)
>      {
> -      _ForwardIterator __cur = __result;
> -      __try
> -       {
> -         for (; __n > 0; --__n, (void) ++__first, ++__cur)
> -           std::_Construct(std::__addressof(*__cur), *__first);
> -         return {__first, __cur};
> -       }
> -      __catch(...)
> -       {
> -         std::_Destroy(__result, __cur);
> -         __throw_exception_again;
> -       }
> +      _UninitDestroyGuard<_ForwardIterator> __guard(__result);
> +      for (; __n > 0; --__n, (void) ++__first, ++__result)
> +       std::_Construct(std::__addressof(*__result), *__first);
> +      __guard.release();
> +      return {__first, __result};
>      }
>
>    template<typename _RandomAccessIterator, typename _Size,
> --
> 2.45.2
>
Ville Voutilainen July 3, 2024, 3:36 p.m. UTC | #2
On Wed, 3 Jul 2024 at 18:33, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On Thu, 27 Jun 2024 at 11:52, Jonathan Wakely wrote:
> >
> > This refactoring to use RAII doesn't seem to make any difference in
> > benchmarks, although the generated code for some std::vector operations
> > seems to be slightly larger. Maybe it will be faster (or slower) in some
> > cases I didn't test?
> >
> > I think I like the change anyway - any other opinions on whether it's an
> > improvement?
>
> Any thoughts before I push this? Better? Worse? Needs more cowbell?

I think the patch is an improvement. Push it.
Jonathan Wakely July 5, 2024, 11:23 a.m. UTC | #3
Thanks for the feedback - pushed.

On Wed, 3 Jul 2024 at 16:37, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
>
> On Wed, 3 Jul 2024 at 18:33, Jonathan Wakely <jwakely@redhat.com> wrote:
> >
> > On Thu, 27 Jun 2024 at 11:52, Jonathan Wakely wrote:
> > >
> > > This refactoring to use RAII doesn't seem to make any difference in
> > > benchmarks, although the generated code for some std::vector operations
> > > seems to be slightly larger. Maybe it will be faster (or slower) in some
> > > cases I didn't test?
> > >
> > > I think I like the change anyway - any other opinions on whether it's an
> > > improvement?
> >
> > Any thoughts before I push this? Better? Worse? Needs more cowbell?
>
> I think the patch is an improvement. Push it.
>
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h
index 3c405d8fbe8..a9965f26269 100644
--- a/libstdc++-v3/include/bits/stl_uninitialized.h
+++ b/libstdc++-v3/include/bits/stl_uninitialized.h
@@ -107,24 +107,70 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __is_trivial(T) && __is_assignable(T&, U)
 #endif
 
+  template<typename _ForwardIterator, typename _Alloc = void>
+    struct _UninitDestroyGuard
+    {
+      _GLIBCXX20_CONSTEXPR
+      explicit
+      _UninitDestroyGuard(_ForwardIterator& __first, _Alloc& __a)
+      : _M_first(__first), _M_cur(__builtin_addressof(__first)), _M_alloc(__a)
+      { }
+
+      _GLIBCXX20_CONSTEXPR
+      ~_UninitDestroyGuard()
+      {
+	if (__builtin_expect(_M_cur != 0, 0))
+	  std::_Destroy(_M_first, *_M_cur, _M_alloc);
+      }
+
+      _GLIBCXX20_CONSTEXPR
+      void release() { _M_cur = 0; }
+
+    private:
+      _ForwardIterator const _M_first;
+      _ForwardIterator* _M_cur;
+      _Alloc& _M_alloc;
+
+      _UninitDestroyGuard(const _UninitDestroyGuard&);
+    };
+
+  template<typename _ForwardIterator>
+    struct _UninitDestroyGuard<_ForwardIterator, void>
+    {
+      _GLIBCXX20_CONSTEXPR
+      explicit
+      _UninitDestroyGuard(_ForwardIterator& __first)
+      : _M_first(__first), _M_cur(__builtin_addressof(__first))
+      { }
+
+      _GLIBCXX20_CONSTEXPR
+      ~_UninitDestroyGuard()
+      {
+	if (__builtin_expect(_M_cur != 0, 0))
+	  std::_Destroy(_M_first, *_M_cur);
+      }
+
+      _GLIBCXX20_CONSTEXPR
+      void release() { _M_cur = 0; }
+
+      _ForwardIterator const _M_first;
+      _ForwardIterator* _M_cur;
+
+    private:
+      _UninitDestroyGuard(const _UninitDestroyGuard&);
+    };
+
   template<typename _InputIterator, typename _ForwardIterator>
     _GLIBCXX20_CONSTEXPR
     _ForwardIterator
     __do_uninit_copy(_InputIterator __first, _InputIterator __last,
 		     _ForwardIterator __result)
     {
-      _ForwardIterator __cur = __result;
-      __try
-	{
-	  for (; __first != __last; ++__first, (void)++__cur)
-	    std::_Construct(std::__addressof(*__cur), *__first);
-	  return __cur;
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__result, __cur);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator> __guard(__result);
+      for (; __first != __last; ++__first, (void)++__result)
+	std::_Construct(std::__addressof(*__result), *__first);
+      __guard.release();
+      return __result;
     }
 
   template<bool _TrivialValueTypes>
@@ -192,17 +238,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __do_uninit_fill(_ForwardIterator __first, _ForwardIterator __last,
 		     const _Tp& __x)
     {
-      _ForwardIterator __cur = __first;
-      __try
-	{
-	  for (; __cur != __last; ++__cur)
-	    std::_Construct(std::__addressof(*__cur), __x);
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__first, __cur);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+      for (; __first != __last; ++__first)
+	std::_Construct(std::__addressof(*__first), __x);
+      __guard.release();
     }
 
   template<bool _TrivialValueType>
@@ -260,18 +299,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     _ForwardIterator
     __do_uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
     {
-      _ForwardIterator __cur = __first;
-      __try
-	{
-	  for (; __n > 0; --__n, (void) ++__cur)
-	    std::_Construct(std::__addressof(*__cur), __x);
-	  return __cur;
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__first, __cur);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+      for (; __n > 0; --__n, (void) ++__first)
+	std::_Construct(std::__addressof(*__first), __x);
+      __guard.release();
+      return __first;
     }
 
   template<bool _TrivialValueType>
@@ -344,19 +376,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __uninitialized_copy_a(_InputIterator __first, _InputIterator __last,
 			   _ForwardIterator __result, _Allocator& __alloc)
     {
-      _ForwardIterator __cur = __result;
-      __try
-	{
-	  typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
-	  for (; __first != __last; ++__first, (void)++__cur)
-	    __traits::construct(__alloc, std::__addressof(*__cur), *__first);
-	  return __cur;
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__result, __cur, __alloc);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator, _Allocator>
+	__guard(__result, __alloc);
+
+      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
+      for (; __first != __last; ++__first, (void)++__result)
+	__traits::construct(__alloc, std::__addressof(*__result), *__first);
+      __guard.release();
+      return __result;
     }
 
 #if _GLIBCXX_HOSTED
@@ -406,18 +433,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __uninitialized_fill_a(_ForwardIterator __first, _ForwardIterator __last,
 			   const _Tp& __x, _Allocator& __alloc)
     {
-      _ForwardIterator __cur = __first;
-      __try
-	{
-	  typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
-	  for (; __cur != __last; ++__cur)
-	    __traits::construct(__alloc, std::__addressof(*__cur), __x);
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__first, __cur, __alloc);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator, _Allocator>
+	__guard(__first, __alloc);
+
+      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
+      for (; __first != __last; ++__first)
+	__traits::construct(__alloc, std::__addressof(*__first), __x);
+
+      __guard.release();
     }
 
 #if _GLIBCXX_HOSTED
@@ -442,19 +465,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n,
 			     const _Tp& __x, _Allocator& __alloc)
     {
-      _ForwardIterator __cur = __first;
-      __try
-	{
-	  typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
-	  for (; __n > 0; --__n, (void) ++__cur)
-	    __traits::construct(__alloc, std::__addressof(*__cur), __x);
-	  return __cur;
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__first, __cur, __alloc);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator, _Allocator>
+	__guard(__first, __alloc);
+      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
+      for (; __n > 0; --__n, (void) ++__first)
+	__traits::construct(__alloc, std::__addressof(*__first), __x);
+      __guard.release();
+      return __first;
     }
 
 #if _GLIBCXX_HOSTED
@@ -493,17 +510,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			      _Allocator& __alloc)
     {
       _ForwardIterator __mid = std::__uninitialized_copy_a(__first1, __last1,
-							   __result,
-							   __alloc);
-      __try
-	{
-	  return std::__uninitialized_move_a(__first2, __last2, __mid, __alloc);
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__result, __mid, __alloc);
-	  __throw_exception_again;
-	}
+							   __result, __alloc);
+      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__result,
+								__alloc);
+      __result = __mid; // Everything up to __mid is now guarded.
+      __result = std::__uninitialized_move_a(__first2, __last2, __mid, __alloc);
+      __guard.release();
+      return __result;
     }
 
   // __uninitialized_move_copy
@@ -521,17 +534,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			      _Allocator& __alloc)
     {
       _ForwardIterator __mid = std::__uninitialized_move_a(__first1, __last1,
-							   __result,
-							   __alloc);
-      __try
-	{
-	  return std::__uninitialized_copy_a(__first2, __last2, __mid, __alloc);
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__result, __mid, __alloc);
-	  __throw_exception_again;
-	}
+							   __result, __alloc);
+      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__result,
+								__alloc);
+      __result = __mid; // Everything up to __mid is now guarded.
+      __result = std::__uninitialized_copy_a(__first2, __last2, __mid, __alloc);
+      __guard.release();
     }
 
   // __uninitialized_fill_move
@@ -545,15 +553,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			      _InputIterator __last, _Allocator& __alloc)
     {
       std::__uninitialized_fill_a(__result, __mid, __x, __alloc);
-      __try
-	{
-	  return std::__uninitialized_move_a(__first, __last, __mid, __alloc);
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__result, __mid, __alloc);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__result,
+								__alloc);
+      __result = __mid; // Everything up to __mid is now guarded.
+      __result = std::__uninitialized_move_a(__first, __last, __mid, __alloc);
+      __guard.release();
+      return __result;
     }
 
   // __uninitialized_move_fill
@@ -570,15 +575,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _ForwardIterator __mid2 = std::__uninitialized_move_a(__first1, __last1,
 							    __first2,
 							    __alloc);
-      __try
-	{
-	  std::__uninitialized_fill_a(__mid2, __last2, __x, __alloc);
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__first2, __mid2, __alloc);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__first2,
+								__alloc);
+      __first2 = __mid2; // Everything up to __mid2 is now guarded.
+      std::__uninitialized_fill_a(__mid2, __last2, __x, __alloc);
+      __guard.release();
     }
 
   /// @endcond
@@ -596,17 +597,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
         static void
         __uninit_default(_ForwardIterator __first, _ForwardIterator __last)
         {
-	  _ForwardIterator __cur = __first;
-	  __try
-	    {
-	      for (; __cur != __last; ++__cur)
-		std::_Construct(std::__addressof(*__cur));
-	    }
-	  __catch(...)
-	    {
-	      std::_Destroy(__first, __cur);
-	      __throw_exception_again;
-	    }
+	  _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+	  for (; __first != __last; ++__first)
+	    std::_Construct(std::__addressof(*__first));
+	  __guard.release();
 	}
     };
 
@@ -636,18 +630,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
         static _ForwardIterator
         __uninit_default_n(_ForwardIterator __first, _Size __n)
         {
-	  _ForwardIterator __cur = __first;
-	  __try
-	    {
-	      for (; __n > 0; --__n, (void) ++__cur)
-		std::_Construct(std::__addressof(*__cur));
-	      return __cur;
-	    }
-	  __catch(...)
-	    {
-	      std::_Destroy(__first, __cur);
-	      __throw_exception_again;
-	    }
+	  _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+	  for (; __n > 0; --__n, (void) ++__first)
+	    std::_Construct(std::__addressof(*__first));
+	  __guard.release();
+	  return __first;
 	}
     };
 
@@ -722,18 +709,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			      _ForwardIterator __last,
 			      _Allocator& __alloc)
     {
-      _ForwardIterator __cur = __first;
-      __try
-	{
-	  typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
-	  for (; __cur != __last; ++__cur)
-	    __traits::construct(__alloc, std::__addressof(*__cur));
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__first, __cur, __alloc);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__first,
+								__alloc);
+      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
+      for (; __first != __last; ++__first)
+	__traits::construct(__alloc, std::__addressof(*__first));
+      __guard.release();
     }
 
 #if _GLIBCXX_HOSTED
@@ -753,19 +734,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __uninitialized_default_n_a(_ForwardIterator __first, _Size __n,
 				_Allocator& __alloc)
     {
-      _ForwardIterator __cur = __first;
-      __try
-	{
-	  typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
-	  for (; __n > 0; --__n, (void) ++__cur)
-	    __traits::construct(__alloc, std::__addressof(*__cur));
-	  return __cur;
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__first, __cur, __alloc);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator, _Allocator> __guard(__first,
+								__alloc);
+      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
+      for (; __n > 0; --__n, (void) ++__first)
+	__traits::construct(__alloc, std::__addressof(*__first));
+      __guard.release();
+      return __first;
     }
 
 #if _GLIBCXX_HOSTED
@@ -787,17 +762,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	__uninit_default_novalue(_ForwardIterator __first,
 				 _ForwardIterator __last)
 	{
-	  _ForwardIterator __cur = __first;
-	  __try
-	    {
-	      for (; __cur != __last; ++__cur)
-		std::_Construct_novalue(std::__addressof(*__cur));
-	    }
-	  __catch(...)
-	    {
-	      std::_Destroy(__first, __cur);
-	      __throw_exception_again;
-	    }
+	  _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+	  for (; __first != __last; ++__first)
+	    std::_Construct_novalue(std::__addressof(*__first));
+	  __guard.release();
 	}
     };
 
@@ -818,18 +786,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	static _ForwardIterator
 	__uninit_default_novalue_n(_ForwardIterator __first, _Size __n)
 	{
-	  _ForwardIterator __cur = __first;
-	  __try
-	    {
-	      for (; __n > 0; --__n, (void) ++__cur)
-		std::_Construct_novalue(std::__addressof(*__cur));
-	      return __cur;
-	    }
-	  __catch(...)
-	    {
-	      std::_Destroy(__first, __cur);
-	      __throw_exception_again;
-	    }
+	  _UninitDestroyGuard<_ForwardIterator> __guard(__first);
+	  for (; __n > 0; --__n, (void) ++__first)
+	    std::_Construct_novalue(std::__addressof(*__first));
+	  __guard.release();
+	  return __first;
 	}
     };
 
@@ -877,18 +838,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __uninitialized_copy_n(_InputIterator __first, _Size __n,
 			   _ForwardIterator __result, input_iterator_tag)
     {
-      _ForwardIterator __cur = __result;
-      __try
-	{
-	  for (; __n > 0; --__n, (void) ++__first, ++__cur)
-	    std::_Construct(std::__addressof(*__cur), *__first);
-	  return __cur;
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__result, __cur);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator> __guard(__result);
+      for (; __n > 0; --__n, (void) ++__first, ++__result)
+	std::_Construct(std::__addressof(*__result), *__first);
+      __guard.release();
+      return __result;
     }
 
   template<typename _RandomAccessIterator, typename _Size,
@@ -903,20 +857,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	   typename _ForwardIterator>
     pair<_InputIterator, _ForwardIterator>
     __uninitialized_copy_n_pair(_InputIterator __first, _Size __n,
-			   _ForwardIterator __result, input_iterator_tag)
+				_ForwardIterator __result, input_iterator_tag)
     {
-      _ForwardIterator __cur = __result;
-      __try
-	{
-	  for (; __n > 0; --__n, (void) ++__first, ++__cur)
-	    std::_Construct(std::__addressof(*__cur), *__first);
-	  return {__first, __cur};
-	}
-      __catch(...)
-	{
-	  std::_Destroy(__result, __cur);
-	  __throw_exception_again;
-	}
+      _UninitDestroyGuard<_ForwardIterator> __guard(__result);
+      for (; __n > 0; --__n, (void) ++__first, ++__result)
+	std::_Construct(std::__addressof(*__result), *__first);
+      __guard.release();
+      return {__first, __result};
     }
 
   template<typename _RandomAccessIterator, typename _Size,