Am Do., 22. Mai 2025 um 12:25 Uhr schrieb Tomasz Kaminski < tkami...@redhat.com>:
> > > On Thu, May 22, 2025 at 12:21 PM Daniel Krügler <daniel.krueg...@gmail.com> > wrote: > >> >> >> Am Do., 22. Mai 2025 um 11:41 Uhr schrieb Tomasz Kamiński < >> tkami...@redhat.com>: >> >>> From: Jonathan Wakely <jwak...@redhat.com> >>> >>> libstdc++-v3/ChangeLog: >>> >>> * include/bits/allocated_ptr.h (_Scoped_allocation): New class >>> template. >>> >>> Co-Authored-By: Tomasz Kamiński <tkami...@redhat.com> >>> Signed-off-by: Tomasz Kamiński <tkami...@redhat.com> >>> --- >>> Tested on x86_64-linux. OK for trunk? >>> >>> libstdc++-v3/include/bits/allocated_ptr.h | 96 +++++++++++++++++++++++ >>> 1 file changed, 96 insertions(+) >>> >>> diff --git a/libstdc++-v3/include/bits/allocated_ptr.h >>> b/libstdc++-v3/include/bits/allocated_ptr.h >>> index 0b2b6fe5820..aa5355f0e2f 100644 >>> --- a/libstdc++-v3/include/bits/allocated_ptr.h >>> +++ b/libstdc++-v3/include/bits/allocated_ptr.h >>> @@ -36,6 +36,7 @@ >>> # include <type_traits> >>> # include <bits/ptr_traits.h> >>> # include <bits/alloc_traits.h> >>> +# include <bits/utility.h> >>> >>> namespace std _GLIBCXX_VISIBILITY(default) >>> { >>> @@ -136,6 +137,101 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >>> return { std::__allocate_guarded(__a) }; >>> } >>> >>> + // An RAII type that acquires memory from an allocator. >>> + // N.B. 'scoped' here in in the RAII sense, not the scoped allocator >>> model, >>> + // so this has nothing to do with `std::scoped_allocator_adaptor`. >>> + // This class can be used to simplify the common pattern: >>> + // >>> + // auto ptr = alloc.allocate(1); >>> + // try { >>> + // std::construct_at(std::to_address(ptr), args); >>> + // m_ptr = ptr; >>> + // } catch (...) { >>> + // alloc.deallocate(ptr, 1); >>> + // throw; >>> + // } >>> + // >>> + // Instead you can do: >>> + // >>> + // _Scoped_allocation sa(alloc); >>> + // m_ptr = std::construct_at(sa.get(), args); >>> + // (void) sa.release(); >>> + // >>> + // Or even simpler: >>> + // >>> + // _Scoped_allocation sa(alloc, std::in_place, args); >>> + // m_ptr = sa.release(); >>> + // >>> + template<typename _Alloc> >>> + struct _Scoped_allocation >>> + { >>> + using value_type = typename allocator_traits<_Alloc>::value_type; >>> + using pointer = typename allocator_traits<_Alloc>::pointer; >>> + >>> + // Use `a` to allocate memory for `n` objects. >>> + constexpr explicit >>> + _Scoped_allocation(const _Alloc& __a, size_t __n = 1) >>> + : _M_a(__a), _M_n(__n), _M_p(_M_a.allocate(__n)) >>> + { } >>> + >>> +#if __glibcxx_optional >= 201606L >>> + // Allocate memory for a single object and if that succeeds, >>> + // construct an object using args. >>> + // >>> + // Does not do uses-allocator construction; don't use if you need >>> that. >>> + // >>> + // CAUTION: the destructor will *not* destroy this object, it >>> will only >>> + // free the memory. That means the following pattern is unsafe: >>> + // >>> + // _Scoped_allocation sa(alloc, in_place, args); >>> + // potentially_throwing_operations(); >>> + // return sa.release(); >>> + // >>> + // If the middle operation throws, the object will not be >>> destroyed. >>> + template<typename... _Args> >>> + constexpr explicit >>> + _Scoped_allocation(const _Alloc& __a, in_place_t, _Args&&... >>> __args) >>> + : _Scoped_allocation(__a, 1) >>> + { >>> + // The target constructor has completed, so if the next line >>> throws, >>> + // the destructor will deallocate the memory. >>> + allocator_traits<_Alloc>::construct(_M_a, get(), >>> + >>> std::forward<_Args>(__args)...); >>> + } >>> +#endif >>> + >>> + _GLIBCXX20_CONSTEXPR >>> + ~_Scoped_allocation() >>> + { >>> + if (_M_p) [[__unlikely__]] >>> + _M_a.deallocate(_M_p, _M_n); >>> >> >> Why is the situation *unlikely* that _M_p has a non-nullptr content? >> Shouldn't that actually be likely? >> > This object manages allocation of raw memory, and not contained objects. > So the non-exceptional code path > looks like: > _Scoped_allocation a(alloc, in_place, argos); > _M_ptr = a.release(); > And release set the _M_p to nullptr. > > In other words, this if is taken only in case of exception. > Got it - thanks! - Daniel