libstdc++: allocated_ptr.h Source File

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
41namespace 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.
198 allocator_traits<_Alloc>::construct(_M_a, get(),
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
type_traits
ptr_traits.h
utility.h
std::operator*
constexpr complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition complex:434
std::__addressof
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
std::forward
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
std
ISO C++ entities toplevel namespace is std.
std::allocator_traits::allocate
static constexpr pointer allocate(_Alloc &__a, size_type __n)
Allocate memory.
Definition bits/alloc_traits.h:380
std::allocator_traits::deallocate
static constexpr void deallocate(_Alloc &__a, pointer __p, size_type __n)
Deallocate memory.
Definition bits/alloc_traits.h:435
alloc_traits.h