On Fri, May 9, 2025 at 6:00 PM Tomasz Kamiński <[email protected]> wrote:
> This patch adds a _Guard_nodes scope guard nested to the _Deque_base,
> that deallocates the range of nodes, and replaces __try/__catch block
> with appropriately constructed guard object.
>
> libstdc++-v3/ChangeLog:
>
> * include/bits/deque.tcc (_Deque_base::_Guard_nodes): Define.
> (_Deque_base::_M_create_nodes): Moved defintion from stl_deque.h
> and replace __try/__catch with _Guard_nodes scope object.
> (deque::_M_fill_insert, deque::_M_default_append)
> (deque::_M_push_back_aux, deque::_M_push_front_aux)
> (deque::_M_range_prepend, deque::_M_range_append,
> deque::_M_insert_aux):
> Replace __try/__catch with _Guard_nodes scope object.
> (deque::_M_new_elements_at_back, deque::_M_new_elements_at_back):
> Use
> _M_create_nodes.
> * include/bits/stl_deque.h (_Deque_base::_Guard_nodes): Declare.
> (_Deque_base<_Tp, _Alloc)::_M_create_nodes): Move defintion to
> deque.tcc.
> (deque::_Guard_nodes): Add typedef, so name is found by lookup.
> * testsuite/23_containers/deque/modifiers/push_back/throw.cc: New
> test.
> ---
> Fixed the off-by-one error in _M_push_back_aux and added test that
> reliably detecst it.
> Updated description and removed new line before struct.
> Tested on x86_64 linux. Separately tested push_back/throw.cc with all
> standards.
> OK for trunk?
>
Ping, would like to merge it in the new year.
>
>
> libstdc++-v3/include/bits/deque.tcc | 423 ++++++++----------
> libstdc++-v3/include/bits/stl_deque.h | 20 +-
> .../deque/modifiers/push_back/throw.cc | 56 +++
> 3 files changed, 251 insertions(+), 248 deletions(-)
> create mode 100644
> libstdc++-v3/testsuite/23_containers/deque/modifiers/push_back/throw.cc
>
> diff --git a/libstdc++-v3/include/bits/deque.tcc
> b/libstdc++-v3/include/bits/deque.tcc
> index dabb6ec5365..71c4f13170a 100644
> --- a/libstdc++-v3/include/bits/deque.tcc
> +++ b/libstdc++-v3/include/bits/deque.tcc
> @@ -63,6 +63,39 @@ namespace std _GLIBCXX_VISIBILITY(default)
> _GLIBCXX_BEGIN_NAMESPACE_VERSION
> _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>
> + template<typename _Tp, typename _Alloc>
> + struct _Deque_base<_Tp, _Alloc>::_Guard_nodes
> + {
> + _Guard_nodes(_Deque_base& __self,
> + _Map_pointer __first, _Map_pointer __last)
> + : _M_self(__self), _M_first(__first), _M_last(__last)
> + { }
> +
> + ~_Guard_nodes()
> + { _M_self._M_destroy_nodes(_M_first, _M_last); }
> +
> + void _M_disarm()
> + { _M_first = _M_last; }
> +
> + _Deque_base& _M_self;
> + _Map_pointer _M_first;
> + _Map_pointer _M_last;
> +
> + private:
> + _Guard_nodes(_Guard_nodes const&);
> + };
> +
> + template<typename _Tp, typename _Alloc>
> + void
> + _Deque_base<_Tp, _Alloc>::
> + _M_create_nodes(_Map_pointer __nstart, _Map_pointer __nfinish)
> + {
> + _Guard_nodes __guard(*this, __nstart, __nstart);
> + for (_Map_pointer& __cur = __guard._M_last; __cur < __nfinish;
> ++__cur)
> + *__cur = this->_M_allocate_node();
> + __guard._M_disarm();
> + }
> +
> #if __cplusplus >= 201103L
> template <typename _Tp, typename _Alloc>
> void
> @@ -310,35 +343,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> if (__pos._M_cur == this->_M_impl._M_start._M_cur)
> {
> iterator __new_start = _M_reserve_elements_at_front(__n);
> - __try
> - {
> - std::__uninitialized_fill_a(__new_start,
> this->_M_impl._M_start,
> - __x, _M_get_Tp_allocator());
> - this->_M_impl._M_start = __new_start;
> - }
> - __catch(...)
> - {
> - _M_destroy_nodes(__new_start._M_node,
> - this->_M_impl._M_start._M_node);
> - __throw_exception_again;
> - }
> + _Guard_nodes __guard(*this, __new_start._M_node,
> + this->_M_impl._M_start._M_node);
> +
> + std::__uninitialized_fill_a(__new_start, this->_M_impl._M_start,
> + __x, _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_start = __new_start;
> }
> else if (__pos._M_cur == this->_M_impl._M_finish._M_cur)
> {
> iterator __new_finish = _M_reserve_elements_at_back(__n);
> - __try
> - {
> - std::__uninitialized_fill_a(this->_M_impl._M_finish,
> - __new_finish, __x,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_finish = __new_finish;
> - }
> - __catch(...)
> - {
> - _M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
> - __new_finish._M_node + 1);
> - __throw_exception_again;
> - }
> + _Guard_nodes __guard(*this, this->_M_impl._M_finish._M_node + 1,
> + __new_finish._M_node + 1);
> +
> + std::__uninitialized_fill_a(this->_M_impl._M_finish,
> + __new_finish, __x,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_finish = __new_finish;
> }
> else
> _M_insert_aux(__pos, __n, __x);
> @@ -350,23 +373,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> deque<_Tp, _Alloc>::
> _M_default_append(size_type __n)
> {
> - if (__n)
> - {
> - iterator __new_finish = _M_reserve_elements_at_back(__n);
> - __try
> - {
> - std::__uninitialized_default_a(this->_M_impl._M_finish,
> - __new_finish,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_finish = __new_finish;
> - }
> - __catch(...)
> - {
> - _M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
> - __new_finish._M_node + 1);
> - __throw_exception_again;
> - }
> - }
> + if (!__n)
> + return;
> +
> + iterator __new_finish = _M_reserve_elements_at_back(__n);
> + _Guard_nodes __guard(*this, this->_M_impl._M_finish._M_node + 1,
> + __new_finish._M_node + 1);
> +
> + std::__uninitialized_default_a(this->_M_impl._M_finish,
> + __new_finish,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_finish = __new_finish;
> }
>
> template <typename _Tp, typename _Alloc>
> @@ -495,24 +513,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>
> _M_reserve_map_at_back();
> *(this->_M_impl._M_finish._M_node + 1) = this->_M_allocate_node();
> - __try
> - {
> + _Guard_nodes __guard(*this, this->_M_impl._M_finish._M_node + 1,
> + this->_M_impl._M_finish._M_node + 2);
> #if __cplusplus >= 201103L
> - _Alloc_traits::construct(this->_M_impl,
> - this->_M_impl._M_finish._M_cur,
> - std::forward<_Args>(__args)...);
> + _Alloc_traits::construct(this->_M_impl,
> + this->_M_impl._M_finish._M_cur,
> + std::forward<_Args>(__args)...);
> #else
> - this->_M_impl.construct(this->_M_impl._M_finish._M_cur, __t);
> + this->_M_impl.construct(this->_M_impl._M_finish._M_cur, __t);
> #endif
> -
> this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node
> - + 1);
> - this->_M_impl._M_finish._M_cur =
> this->_M_impl._M_finish._M_first;
> - }
> - __catch(...)
> - {
> - _M_deallocate_node(*(this->_M_impl._M_finish._M_node + 1));
> - __throw_exception_again;
> - }
> + __guard._M_disarm();
> +
> this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node + 1);
> + this->_M_impl._M_finish._M_cur = this->_M_impl._M_finish._M_first;
> }
>
> // Called only if _M_impl._M_start._M_cur == _M_impl._M_start._M_first.
> @@ -534,25 +546,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>
> _M_reserve_map_at_front();
> *(this->_M_impl._M_start._M_node - 1) = this->_M_allocate_node();
> - __try
> - {
> -
> this->_M_impl._M_start._M_set_node(this->_M_impl._M_start._M_node
> - - 1);
> - this->_M_impl._M_start._M_cur = this->_M_impl._M_start._M_last
> - 1;
> + _Guard_nodes __guard(*this, this->_M_impl._M_start._M_node - 1,
> + this->_M_impl._M_start._M_node);
> +
> + iterator __new_start;
> + __new_start._M_set_node(this->_M_impl._M_start._M_node - 1);
> + __new_start._M_cur = __new_start._M_last - 1;
> #if __cplusplus >= 201103L
> - _Alloc_traits::construct(this->_M_impl,
> - this->_M_impl._M_start._M_cur,
> - std::forward<_Args>(__args)...);
> + _Alloc_traits::construct(this->_M_impl,
> + __new_start._M_cur,
> + std::forward<_Args>(__args)...);
> #else
> - this->_M_impl.construct(this->_M_impl._M_start._M_cur, __t);
> + this->_M_impl.construct(__new_start._M_cur, __t);
> #endif
> - }
> - __catch(...)
> - {
> - ++this->_M_impl._M_start;
> - _M_deallocate_node(*(this->_M_impl._M_start._M_node - 1));
> - __throw_exception_again;
> - }
> + __guard._M_disarm();
> + this->_M_impl._M_start = __new_start;
> }
>
> // Called only if _M_impl._M_finish._M_cur ==
> _M_impl._M_finish._M_first.
> @@ -591,18 +599,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> size_type __n)
> {
> iterator __new_start = _M_reserve_elements_at_front(__n);
> - __try
> - {
> - std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,
> - __new_start,
> _M_get_Tp_allocator());
> - this->_M_impl._M_start = __new_start;
> - }
> - __catch(...)
> - {
> - _M_destroy_nodes(__new_start._M_node,
> - this->_M_impl._M_start._M_node);
> - __throw_exception_again;
> - }
> + _Guard_nodes __guard(*this, __new_start._M_node,
> + this->_M_impl._M_start._M_node);
> +
> + std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,
> + __new_start, _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_start = __new_start;
> }
>
> template <typename _Tp, typename _Alloc>
> @@ -613,19 +616,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> size_type __n)
> {
> iterator __new_finish = _M_reserve_elements_at_back(__n);
> - __try
> - {
> - std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,
> - this->_M_impl._M_finish,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_finish = __new_finish;
> - }
> - __catch(...)
> - {
> - _M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
> - __new_finish._M_node + 1);
> - __throw_exception_again;
> - }
> + _Guard_nodes __guard(*this, this->_M_impl._M_finish._M_node + 1,
> + __new_finish._M_node + 1);
> +
> + std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,
> + this->_M_impl._M_finish,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_finish = __new_finish;
> }
>
> template <typename _Tp, typename _Alloc>
> @@ -712,35 +710,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> iterator __new_start = _M_reserve_elements_at_front(__n);
> iterator __old_start = this->_M_impl._M_start;
> __pos = this->_M_impl._M_start + __elems_before;
> - __try
> +
> + _Guard_nodes __guard(*this, __new_start._M_node,
> + this->_M_impl._M_start._M_node);
> + if (__elems_before >= difference_type(__n))
> {
> - if (__elems_before >= difference_type(__n))
> - {
> - iterator __start_n = (this->_M_impl._M_start
> - + difference_type(__n));
> - std::__uninitialized_move_a(this->_M_impl._M_start,
> - __start_n, __new_start,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_start = __new_start;
> - _GLIBCXX_MOVE3(__start_n, __pos, __old_start);
> - std::fill(__pos - difference_type(__n), __pos, __x_copy);
> - }
> - else
> - {
> - std::__uninitialized_move_fill(this->_M_impl._M_start,
> - __pos, __new_start,
> - this->_M_impl._M_start,
> - __x_copy,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_start = __new_start;
> - std::fill(__old_start, __pos, __x_copy);
> - }
> + iterator __start_n = (this->_M_impl._M_start
> + + difference_type(__n));
> + std::__uninitialized_move_a(this->_M_impl._M_start,
> + __start_n, __new_start,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_start = __new_start;
> + _GLIBCXX_MOVE3(__start_n, __pos, __old_start);
> + std::fill(__pos - difference_type(__n), __pos, __x_copy);
> }
> - __catch(...)
> + else
> {
> - _M_destroy_nodes(__new_start._M_node,
> - this->_M_impl._M_start._M_node);
> - __throw_exception_again;
> + std::__uninitialized_move_fill(this->_M_impl._M_start,
> + __pos, __new_start,
> + this->_M_impl._M_start,
> + __x_copy,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_start = __new_start;
> + std::fill(__old_start, __pos, __x_copy);
> }
> }
> else
> @@ -750,36 +744,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> const difference_type __elems_after =
> difference_type(__length) - __elems_before;
> __pos = this->_M_impl._M_finish - __elems_after;
> - __try
> +
> + _Guard_nodes __guard(*this, this->_M_impl._M_finish._M_node + 1,
> + __new_finish._M_node + 1);
> + if (__elems_after > difference_type(__n))
> {
> - if (__elems_after > difference_type(__n))
> - {
> - iterator __finish_n = (this->_M_impl._M_finish
> - - difference_type(__n));
> - std::__uninitialized_move_a(__finish_n,
> - this->_M_impl._M_finish,
> - this->_M_impl._M_finish,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_finish = __new_finish;
> - _GLIBCXX_MOVE_BACKWARD3(__pos, __finish_n, __old_finish);
> - std::fill(__pos, __pos + difference_type(__n), __x_copy);
> - }
> - else
> - {
> - std::__uninitialized_fill_move(this->_M_impl._M_finish,
> - __pos +
> difference_type(__n),
> - __x_copy, __pos,
> - this->_M_impl._M_finish,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_finish = __new_finish;
> - std::fill(__pos, __old_finish, __x_copy);
> - }
> + iterator __finish_n = (this->_M_impl._M_finish
> + - difference_type(__n));
> + std::__uninitialized_move_a(__finish_n,
> + this->_M_impl._M_finish,
> + this->_M_impl._M_finish,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_finish = __new_finish;
> + _GLIBCXX_MOVE_BACKWARD3(__pos, __finish_n, __old_finish);
> + std::fill(__pos, __pos + difference_type(__n), __x_copy);
> }
> - __catch(...)
> + else
> {
> - _M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
> - __new_finish._M_node + 1);
> - __throw_exception_again;
> + std::__uninitialized_fill_move(this->_M_impl._M_finish,
> + __pos + difference_type(__n),
> + __x_copy, __pos,
> + this->_M_impl._M_finish,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_finish = __new_finish;
> + std::fill(__pos, __old_finish, __x_copy);
> }
> }
> }
> @@ -799,36 +789,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> iterator __new_start = _M_reserve_elements_at_front(__n);
> iterator __old_start = this->_M_impl._M_start;
> __pos = this->_M_impl._M_start + __elemsbefore;
> - __try
> +
> + _Guard_nodes __guard(*this, __new_start._M_node,
> + this->_M_impl._M_start._M_node);
> +
> + if (__elemsbefore >= difference_type(__n))
> {
> - if (__elemsbefore >= difference_type(__n))
> - {
> - iterator __start_n = (this->_M_impl._M_start
> - + difference_type(__n));
> - std::__uninitialized_move_a(this->_M_impl._M_start,
> - __start_n, __new_start,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_start = __new_start;
> - _GLIBCXX_MOVE3(__start_n, __pos, __old_start);
> - std::copy(__first, __last, __pos -
> difference_type(__n));
> - }
> - else
> - {
> - _ForwardIterator __mid = __first;
> - std::advance(__mid, difference_type(__n) -
> __elemsbefore);
> - std::__uninitialized_move_copy(this->_M_impl._M_start,
> - __pos, __first, __mid,
> - __new_start,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_start = __new_start;
> - std::copy(__mid, __last, __old_start);
> - }
> + iterator __start_n = (this->_M_impl._M_start
> + + difference_type(__n));
> + std::__uninitialized_move_a(this->_M_impl._M_start,
> + __start_n, __new_start,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_start = __new_start;
> + _GLIBCXX_MOVE3(__start_n, __pos, __old_start);
> + std::copy(__first, __last, __pos - difference_type(__n));
> }
> - __catch(...)
> + else
> {
> - _M_destroy_nodes(__new_start._M_node,
> - this->_M_impl._M_start._M_node);
> - __throw_exception_again;
> + _ForwardIterator __mid = __first;
> + std::advance(__mid, difference_type(__n) - __elemsbefore);
> + std::__uninitialized_move_copy(this->_M_impl._M_start,
> + __pos, __first, __mid,
> + __new_start,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_start = __new_start;
> + std::copy(__mid, __last, __old_start);
> }
> }
> else
> @@ -838,37 +825,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> const difference_type __elemsafter =
> difference_type(__length) - __elemsbefore;
> __pos = this->_M_impl._M_finish - __elemsafter;
> - __try
> +
> + _Guard_nodes __guard(*this, this->_M_impl._M_finish._M_node + 1,
> + __new_finish._M_node + 1);
> + if (__elemsafter > difference_type(__n))
> {
> - if (__elemsafter > difference_type(__n))
> - {
> - iterator __finish_n = (this->_M_impl._M_finish
> - - difference_type(__n));
> - std::__uninitialized_move_a(__finish_n,
> - this->_M_impl._M_finish,
> - this->_M_impl._M_finish,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_finish = __new_finish;
> - _GLIBCXX_MOVE_BACKWARD3(__pos, __finish_n, __old_finish);
> - std::copy(__first, __last, __pos);
> - }
> - else
> - {
> - _ForwardIterator __mid = __first;
> - std::advance(__mid, __elemsafter);
> - std::__uninitialized_copy_move(__mid, __last, __pos,
> - this->_M_impl._M_finish,
> - this->_M_impl._M_finish,
> - _M_get_Tp_allocator());
> - this->_M_impl._M_finish = __new_finish;
> - std::copy(__first, __mid, __pos);
> - }
> + iterator __finish_n = (this->_M_impl._M_finish
> + - difference_type(__n));
> + std::__uninitialized_move_a(__finish_n,
> + this->_M_impl._M_finish,
> + this->_M_impl._M_finish,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_finish = __new_finish;
> + _GLIBCXX_MOVE_BACKWARD3(__pos, __finish_n, __old_finish);
> + std::copy(__first, __last, __pos);
> }
> - __catch(...)
> + else
> {
> - _M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
> - __new_finish._M_node + 1);
> - __throw_exception_again;
> + _ForwardIterator __mid = __first;
> + std::advance(__mid, __elemsafter);
> + std::__uninitialized_copy_move(__mid, __last, __pos,
> + this->_M_impl._M_finish,
> + this->_M_impl._M_finish,
> + _M_get_Tp_allocator());
> + __guard._M_disarm();
> + this->_M_impl._M_finish = __new_finish;
> + std::copy(__first, __mid, __pos);
> }
> }
> }
> @@ -1057,18 +1040,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> const size_type __new_nodes = ((__new_elems + _S_buffer_size() - 1)
> / _S_buffer_size());
> _M_reserve_map_at_front(__new_nodes);
> - size_type __i;
> - __try
> - {
> - for (__i = 1; __i <= __new_nodes; ++__i)
> - *(this->_M_impl._M_start._M_node - __i) =
> this->_M_allocate_node();
> - }
> - __catch(...)
> - {
> - for (size_type __j = 1; __j < __i; ++__j)
> - _M_deallocate_node(*(this->_M_impl._M_start._M_node - __j));
> - __throw_exception_again;
> - }
> + _M_create_nodes(this->_M_impl._M_start._M_node - __new_nodes,
> + this->_M_impl._M_start._M_node);
> }
>
> template <typename _Tp, typename _Alloc>
> @@ -1082,18 +1055,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> const size_type __new_nodes = ((__new_elems + _S_buffer_size() - 1)
> / _S_buffer_size());
> _M_reserve_map_at_back(__new_nodes);
> - size_type __i;
> - __try
> - {
> - for (__i = 1; __i <= __new_nodes; ++__i)
> - *(this->_M_impl._M_finish._M_node + __i) =
> this->_M_allocate_node();
> - }
> - __catch(...)
> - {
> - for (size_type __j = 1; __j < __i; ++__j)
> - _M_deallocate_node(*(this->_M_impl._M_finish._M_node + __j));
> - __throw_exception_again;
> - }
> + _M_create_nodes(_M_impl._M_finish._M_node + 1,
> + _M_impl._M_finish._M_node + __new_nodes + 1);
> }
>
> template <typename _Tp, typename _Alloc>
> diff --git a/libstdc++-v3/include/bits/stl_deque.h
> b/libstdc++-v3/include/bits/stl_deque.h
> index 8d8ee575a26..73e48299938 100644
> --- a/libstdc++-v3/include/bits/stl_deque.h
> +++ b/libstdc++-v3/include/bits/stl_deque.h
> @@ -612,6 +612,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> void _M_destroy_nodes(_Map_pointer __nstart,
> _Map_pointer __nfinish) _GLIBCXX_NOEXCEPT;
> enum { _S_initial_map_size = 8 };
> + struct _Guard_nodes;
>
> _Deque_impl _M_impl;
> };
> @@ -675,24 +676,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> % __deque_buf_size(sizeof(_Tp)));
> }
>
> - template<typename _Tp, typename _Alloc>
> - void
> - _Deque_base<_Tp, _Alloc>::
> - _M_create_nodes(_Map_pointer __nstart, _Map_pointer __nfinish)
> - {
> - _Map_pointer __cur;
> - __try
> - {
> - for (__cur = __nstart; __cur < __nfinish; ++__cur)
> - *__cur = this->_M_allocate_node();
> - }
> - __catch(...)
> - {
> - _M_destroy_nodes(__nstart, __cur);
> - __throw_exception_again;
> - }
> - }
> -
> template<typename _Tp, typename _Alloc>
> void
> _Deque_base<_Tp, _Alloc>::
> @@ -812,6 +795,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> typedef typename _Base::_Tp_alloc_type _Tp_alloc_type;
> typedef typename _Base::_Alloc_traits _Alloc_traits;
> typedef typename _Base::_Map_pointer _Map_pointer;
> + typedef typename _Base::_Guard_nodes _Guard_nodes;
>
> public:
> typedef _Tp value_type;
> diff --git
> a/libstdc++-v3/testsuite/23_containers/deque/modifiers/push_back/throw.cc
> b/libstdc++-v3/testsuite/23_containers/deque/modifiers/push_back/throw.cc
> new file mode 100644
> index 00000000000..7d4bf6954f2
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/deque/modifiers/push_back/throw.cc
> @@ -0,0 +1,56 @@
> +// { dg-do run }
> +
> +#include <deque>
> +#include <testsuite_hooks.h>
> +#include <testsuite_allocator.h>
> +
> +struct Thrower
> +{
> + Thrower(int p) : v(p) {}
> + Thrower(Thrower const& p) : v(p.v)
> + {
> + if (v < 0)
> + throw v;
> + }
> +
> + int v;
> +};
> +
> +void test01()
> +{
> + using namespace std;
> + typedef __gnu_test::uneq_allocator<Thrower> Allocator;
> + typedef __gnu_test::uneq_allocator_base AllocatorBase;
> +
> + const std::size_t buf_elems =
> _GLIBCXX_STD_C::__deque_buf_size(sizeof(Thrower));
> + std::deque<Thrower, Allocator> d;
> + for (std::size_t i = 1; i < buf_elems; i++)
> + d.push_back(Thrower(i));
> + const AllocatorBase::map_type allocated = AllocatorBase::get_map();
> +
> + try
> + {
> + d.push_back(Thrower(-1));
> + VERIFY( false );
> + }
> + catch (int p)
> + {
> + VERIFY( p == -1 );
> + }
> +
> + VERIFY( d.size() == buf_elems - 1 );
> + for (std::size_t i = 1; i < buf_elems; i++)
> + VERIFY( d[i-1].v == i );
> +
> + const AllocatorBase::map_type& current = AllocatorBase::get_map();
> + VERIFY( current.size() == allocated.size() );
> + for (AllocatorBase::map_type::const_iterator it = current.begin();
> + it != current.end(); ++it)
> + VERIFY( allocated.find(it->first) != allocated.end() );
> +}
> +
> +int main()
> +{
> + test01();
> + return 0;
> +}
> --
> 2.49.0
>
>