libstdc++
allocated_ptr.h
Go to the documentation of this file.
1 // Guarded Allocation -*- C++ -*-
2 
3 // Copyright (C) 2014-2026 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file bits/allocated_ptr.h
26  * This is an internal header file, included by other library headers.
27  * Do not attempt to use it directly. @headername{memory}
28  */
29 
30 #ifndef _ALLOCATED_PTR_H
31 #define _ALLOCATED_PTR_H 1
32 
33 #if __cplusplus < 201103L
34 # include <bits/c++0xwarning.h>
35 #else
36 # include <type_traits>
37 # include <bits/ptr_traits.h>
38 # include <bits/alloc_traits.h>
39 # include <bits/utility.h>
40 
41 namespace std _GLIBCXX_VISIBILITY(default)
42 {
43 _GLIBCXX_BEGIN_NAMESPACE_VERSION
44 /// @cond undocumented
45 
46  /// Non-standard RAII type for managing pointers obtained from allocators.
47  template<typename _Alloc>
48  struct __allocated_ptr
49  {
50  using pointer = typename allocator_traits<_Alloc>::pointer;
51  using value_type = typename allocator_traits<_Alloc>::value_type;
52 
53  /// Take ownership of __ptr
54  __allocated_ptr(_Alloc& __a, pointer __ptr) noexcept
55  : _M_alloc(std::__addressof(__a)), _M_ptr(__ptr)
56  { }
57 
58  /// Convert __ptr to allocator's pointer type and take ownership of it
59  template<typename _Ptr,
60  typename _Req = _Require<is_same<_Ptr, value_type*>>>
61  __allocated_ptr(_Alloc& __a, _Ptr __ptr)
62  : _M_alloc(std::__addressof(__a)),
63  _M_ptr(pointer_traits<pointer>::pointer_to(*__ptr))
64  { }
65 
66  /// Transfer ownership of the owned pointer
67  __allocated_ptr(__allocated_ptr&& __gd) noexcept
68  : _M_alloc(__gd._M_alloc), _M_ptr(__gd._M_ptr)
69  { __gd._M_ptr = nullptr; }
70 
71  /// Deallocate the owned pointer
72  ~__allocated_ptr()
73  {
74  if (_M_ptr != nullptr)
75  std::allocator_traits<_Alloc>::deallocate(*_M_alloc, _M_ptr, 1);
76  }
77 
78  /// Release ownership of the owned pointer
79  __allocated_ptr&
80  operator=(std::nullptr_t) noexcept
81  {
82  _M_ptr = nullptr;
83  return *this;
84  }
85 
86  explicit operator bool() const noexcept { return (bool)_M_ptr; }
87 
88  /// Get the address that the owned pointer refers to.
89  value_type* get() const { return std::__to_address(_M_ptr); }
90 
91  pointer release() { return std::__exchange(_M_ptr, nullptr); }
92 
93  private:
94  _Alloc* _M_alloc;
95  pointer _M_ptr;
96  };
97 
98  /// Allocate space for a single object using __a.
99  template<typename _Alloc>
100  inline __allocated_ptr<_Alloc>
101  __allocate_guarded(_Alloc& __a)
102  {
103  return { __a, std::allocator_traits<_Alloc>::allocate(__a, 1) };
104  }
105 
106  /// RAII type for constructing/destroying an object with an allocated pointer
107  template<typename _Alloc>
108  struct __allocated_obj : __allocated_ptr<_Alloc>
109  {
110  using value_type = typename __allocated_ptr<_Alloc>::value_type;
111 
112  __allocated_obj(__allocated_obj<_Alloc>&&) = default;
113 
114  // Default-initialize a value_type at *__ptr
115  __allocated_obj(__allocated_ptr<_Alloc>&& __ptr)
116  : __allocated_ptr<_Alloc>(std::move(__ptr))
117  { ::new ((void*)this->get()) value_type; }
118 
119  // Call the destructor if an object is owned.
120  ~__allocated_obj()
121  {
122  if (static_cast<bool>(*this))
123  this->get()->~value_type();
124  }
125 
126  using __allocated_ptr<_Alloc>::operator=;
127 
128  value_type& operator*() const { return *this->get(); }
129  value_type* operator->() const { return this->get(); }
130  };
131 
132  /// Construct an object in storage allocated using __a.
133  template<typename _Alloc>
134  inline __allocated_obj<_Alloc>
135  __allocate_guarded_obj(_Alloc& __a)
136  {
137  return { std::__allocate_guarded(__a) };
138  }
139 
140  // An RAII type that acquires memory from an allocator.
141  // N.B. 'scoped' here in in the RAII sense, not the scoped allocator model,
142  // so this has nothing to do with `std::scoped_allocator_adaptor`.
143  // This class can be used to simplify the common pattern:
144  //
145  // auto ptr = alloc.allocate(1);
146  // try {
147  // std::construct_at(std::to_address(ptr), args);
148  // m_ptr = ptr;
149  // } catch (...) {
150  // alloc.deallocate(ptr, 1);
151  // throw;
152  // }
153  //
154  // Instead you can do:
155  //
156  // _Scoped_allocation sa(alloc);
157  // m_ptr = std::construct_at(sa.get(), args);
158  // (void) sa.release();
159  //
160  // Or even simpler:
161  //
162  // _Scoped_allocation sa(alloc, std::in_place, args);
163  // m_ptr = sa.release();
164  //
165  template<typename _Alloc>
166  struct _Scoped_allocation
167  {
168  using value_type = typename allocator_traits<_Alloc>::value_type;
169  using pointer = typename allocator_traits<_Alloc>::pointer;
170 
171  // Use `a` to allocate memory for `n` objects.
172  constexpr explicit
173  _Scoped_allocation(const _Alloc& __a, size_t __n = 1)
174  : _M_a(__a), _M_n(__n), _M_p(_M_a.allocate(__n))
175  { }
176 
177 #if __glibcxx_optional >= 201606L
178  // Allocate memory for a single object and if that succeeds,
179  // construct an object using args.
180  //
181  // Does not do uses-allocator construction; don't use if you need that.
182  //
183  // CAUTION: the destructor will *not* destroy this object, it will only
184  // free the memory. That means the following pattern is unsafe:
185  //
186  // _Scoped_allocation sa(alloc, in_place, args);
187  // potentially_throwing_operations();
188  // return sa.release();
189  //
190  // If the middle operation throws, the object will not be destroyed.
191  template<typename... _Args>
192  constexpr explicit
193  _Scoped_allocation(const _Alloc& __a, in_place_t, _Args&&... __args)
194  : _Scoped_allocation(__a, 1)
195  {
196  // The target constructor has completed, so if the next line throws,
197  // the destructor will deallocate the memory.
199  std::forward<_Args>(__args)...);
200  }
201 #endif
202 
203  _GLIBCXX20_CONSTEXPR
204  ~_Scoped_allocation()
205  {
206  if (_M_p) [[__unlikely__]]
207  _M_a.deallocate(_M_p, _M_n);
208  }
209 
210  _Scoped_allocation(_Scoped_allocation&&) = delete;
211 
212  constexpr _Alloc
213  get_allocator() const noexcept { return _M_a; }
214 
215  constexpr value_type*
216  get() const noexcept
217  { return std::__to_address(_M_p); }
218 
219  [[__nodiscard__]]
220  constexpr pointer
221  release() noexcept { return std::__exchange(_M_p, nullptr); }
222 
223  private:
224  [[__no_unique_address__]] _Alloc _M_a;
225  size_t _M_n;
226  pointer _M_p;
227  };
228 
229 #if __glibcxx_optional >= 201606L && __cpp_deduction_guides >= 201606L
230  template<typename _Alloc, typename... _Args>
231  _Scoped_allocation(_Alloc, in_place_t, _Args...)
232  -> _Scoped_allocation<_Alloc>;
233 #endif
234 
235 /// @endcond
236 _GLIBCXX_END_NAMESPACE_VERSION
237 } // namespace std
238 
239 #endif
240 #endif
_Alloc::value_type value_type
The allocated type.
__detected_or_t< value_type *, __pointer, _Alloc > pointer
The allocator&#39;s pointer type.
ISO C++ entities toplevel namespace is std.
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:52
static constexpr pointer allocate(_Alloc &__a, size_type __n)
Allocate memory.
static constexpr void deallocate(_Alloc &__a, pointer __p, size_type __n)
Deallocate memory.
constexpr complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition: complex:434
requires static __can_construct< _Alloc, _Tp, _Args... > constexpr void construct(_Alloc &__a, _Tp *__p, _Args &&... __args) noexcept(_S_nothrow_construct< _Tp, _Args... >())
Construct an object of type _Tp