mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
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>
This commit is contained in:
committed by
Tomasz Kamiński
parent
c0a2526f09
commit
0faa31da11
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user