On Fri, 9 May 2025 at 16:13, Tomasz Kaminski <tkami...@redhat.com> wrote: > > > > On Thu, May 8, 2025 at 7:46 PM Jonathan Wakely <jwak...@redhat.com> wrote: >> >> On Fri, 18 Apr 2025 at 10:03, Tomasz Kamiński <tkami...@redhat.com> 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 approparietly constructed guard object. >> >> "appropriately" >> >> > >> > libstdc++-v3/ChangeLog: >> > >> > * include/bits/deque.tcc (_Deque_base<_Tp, _Alloc>::_Guard_nodes): >> > Define. >> >> There's no need for the template argument list here, just >> "_Deque_base" is unambiguous (there's no partial or explicit >> specialization that could be disambiguated with template argument >> lists). And just "deque" below. >> >> > (_Deque_base<_Tp, _Alloc>::_M_create_nodes): Moved defintion from >> > stl_deque.h >> > and replace __try/__catch with _Guard_nodes scope object. >> > (deque<_Tp, _Alloc>::_M_fill_insert, deque<_Tp, >> > _Alloc>::_M_default_append) >> > (deque<_Tp, _Alloc>::_M_push_back_aux, deque<_Tp, >> > _Alloc>::_M_push_front_aux) >> > (deque<_Tp, _Alloc>::_M_range_prepend, deque<_Tp, >> > _Alloc>::_M_range_append) >> > (deque<_Tp, _Alloc>::_M_insert_aux): Replace __try/__catch with >> > _Guard_nodes >> > scope object. >> > (deque<_Tp, _Alloc>::_M_new_elements_at_back) >> > (deque<_Tp, _Alloc>::_M_new_elements_at_back): Use _M_create_nodes. >> > * include/bits/stl_deque.h (_Deque_base<_Tp, >> > _Alloc>::_Guard_nodes): Declare. >> > (_Deque_base<_Tp, _Alloc)::_M_create_nodes): Move defintion to >> > deque.tcc. >> > (deque<_Tp, _Alloc>::_Guard_nodes): Add typedef, so name is found >> > by lookup. >> > --- >> > Testing x86_64-linux, default test configuration passed. >> > OK for trunk? >> > >> > libstdc++-v3/include/bits/deque.tcc | 424 ++++++++++++-------------- >> > libstdc++-v3/include/bits/stl_deque.h | 20 +- >> > 2 files changed, 196 insertions(+), 248 deletions(-) >> > >> > diff --git a/libstdc++-v3/include/bits/deque.tcc >> > b/libstdc++-v3/include/bits/deque.tcc >> > index dabb6ec5365..b70eed69294 100644 >> > --- a/libstdc++-v3/include/bits/deque.tcc >> > +++ b/libstdc++-v3/include/bits/deque.tcc >> > @@ -63,6 +63,40 @@ namespace std _GLIBCXX_VISIBILITY(default) >> > _GLIBCXX_BEGIN_NAMESPACE_VERSION >> > _GLIBCXX_BEGIN_NAMESPACE_CONTAINER >> > >> > + template<typename _Tp, typename _Alloc> >> > + struct >> >> No new line here, just "struct _Deque_base...". >> >> > + _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 +344,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 +374,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 +514,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, >> > + this->_M_impl._M_finish._M_node + 1); >> > #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)); >> >> This deallocates _M_node+1 but the guard object guards >> [_M_node,_M_node+1). I think there's an off-by-one error here. > > Yes, indeed. I will also add a test that will detect this.
Thanks. I think the rest of it looked OK, but I'll go over it again carefully. I did wonder about the "early" calls to _M_disarm(), do all the operations after the _M_disarm() calls guarantee not to throw?