[gcc r16-821] libstdc++: Define _Scoped_allocation RAII helper
Tomasz Kaminski
tkaminsk@gcc.gnu.org
Thu May 22 12:47:55 GMT 2025
https://gcc.gnu.org/g:0faa31da113768a626daa294e840ff1b17499ebf
commit r16-821-g0faa31da113768a626daa294e840ff1b17499ebf
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu May 22 10:58:31 2025 +0200
libstdc++: Define _Scoped_allocation RAII helper
libstdc++-v3/ChangeLog:
* include/bits/allocated_ptr.h (_Scoped_allocation): New class
template.
Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
Diff:
---
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 0b2b6fe5820e..aa5355f0e2fc 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);
+ }
+
+ _Scoped_allocation(_Scoped_allocation&&) = delete;
+
+ constexpr _Alloc
+ get_allocator() const noexcept { return _M_a; }
+
+ constexpr value_type*
+ get() const noexcept
+ { return std::__to_address(_M_p); }
+
+ [[__nodiscard__]]
+ constexpr pointer
+ release() noexcept { return std::__exchange(_M_p, nullptr); }
+
+ private:
+ [[__no_unique_address__]] _Alloc _M_a;
+ size_t _M_n;
+ pointer _M_p;
+ };
+
+#if __glibcxx_optional >= 201606L && __cpp_deduction_guides >= 201606L
+ template<typename _Alloc, typename... _Args>
+ _Scoped_allocation(_Alloc, in_place_t, _Args...)
+ -> _Scoped_allocation<_Alloc>;
+#endif
+
/// @endcond
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
More information about the Libstdc++-cvs
mailing list