libstdc++
memory_resource.h
Go to the documentation of this file.
1// <memory_resource> -*- C++ -*-
2
3// Copyright (C) 2018-2025 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 include/bits/memory_resource.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory_resource}
28 */
29
30#ifndef _GLIBCXX_MEMORY_RESOURCE_H
31#define _GLIBCXX_MEMORY_RESOURCE_H 1
32
33#ifdef _GLIBCXX_SYSHDR
34#pragma GCC system_header
35#endif
36
37#if __cplusplus >= 201703L
38
39#include <new> // operator new(size_t, void*)
40#include <cstddef> // size_t, max_align_t, byte
41#include <bits/functexcept.h> // __throw_bad_array_new_length
42#include <bits/uses_allocator.h> // allocator_arg_t, __use_alloc
43#include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc
44#include <ext/numeric_traits.h> // __int_traits
45#include <debug/assertions.h>
46
47#if ! __glibcxx_make_obj_using_allocator
48# include <bits/utility.h> // index_sequence
49# include <tuple> // tuple, forward_as_tuple
50#endif
51
52namespace std _GLIBCXX_VISIBILITY(default)
53{
54_GLIBCXX_BEGIN_NAMESPACE_VERSION
55namespace pmr
56{
57 /// Class `memory_resource`
58 /**
59 * @ingroup pmr
60 * @headerfile memory_resource
61 * @since C++17
62 */
63 class memory_resource
64 {
65 static constexpr size_t _S_max_align = alignof(max_align_t);
66
67 public:
68 memory_resource() = default;
69 memory_resource(const memory_resource&) = default;
70 virtual ~memory_resource(); // key function
71
72 memory_resource& operator=(const memory_resource&) = default;
73
74 [[nodiscard]]
75 void*
76 allocate(size_t __bytes, size_t __alignment = _S_max_align)
77 __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
78 { return ::operator new(__bytes, do_allocate(__bytes, __alignment)); }
79
80 void
81 deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
82 __attribute__((__nonnull__))
83 { return do_deallocate(__p, __bytes, __alignment); }
84
85 [[nodiscard]]
86 bool
87 is_equal(const memory_resource& __other) const noexcept
88 { return do_is_equal(__other); }
89
90 private:
91 virtual void*
92 do_allocate(size_t __bytes, size_t __alignment) = 0;
93
94 virtual void
95 do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
96
97 virtual bool
98 do_is_equal(const memory_resource& __other) const noexcept = 0;
99 };
100
101 [[nodiscard]]
102 inline bool
103 operator==(const memory_resource& __a, const memory_resource& __b) noexcept
104 { return &__a == &__b || __a.is_equal(__b); }
105
106#if __cpp_impl_three_way_comparison < 201907L
107 [[nodiscard]]
108 inline bool
109 operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
110 { return !(__a == __b); }
111#endif
112
113 // C++17 23.12.3 Class template polymorphic_allocator
114
115 /// Class template polymorphic_allocator
116 /**
117 * @ingroup pmr
118 * @headerfile memory_resource
119 * @since C++17
120 */
121 template<typename _Tp>
122 class polymorphic_allocator
123 {
124 // _GLIBCXX_RESOLVE_LIB_DEFECTS
125 // 2975. Missing case for pair construction in polymorphic allocators
126 template<typename _Up>
127 struct __not_pair { using type = void; };
128
129 template<typename _Up1, typename _Up2>
130 struct __not_pair<pair<_Up1, _Up2>> { };
131
132 public:
133 using value_type = _Tp;
134
135 polymorphic_allocator() noexcept
136 {
137 extern memory_resource* get_default_resource() noexcept
138 __attribute__((__returns_nonnull__));
139 _M_resource = get_default_resource();
140 }
141
142 polymorphic_allocator(memory_resource* __r) noexcept
143 __attribute__((__nonnull__))
144 : _M_resource(__r)
145 { _GLIBCXX_DEBUG_ASSERT(__r); }
146
147 polymorphic_allocator(const polymorphic_allocator& __other) = default;
148
149 template<typename _Up>
150 polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
151 : _M_resource(__x.resource())
152 { }
153
154 polymorphic_allocator&
155 operator=(const polymorphic_allocator&) = delete;
156
157 [[nodiscard]]
158 _Tp*
159 allocate(size_t __n)
160 __attribute__((__returns_nonnull__))
161 {
162 if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n)
163 std::__throw_bad_array_new_length();
164 return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
165 alignof(_Tp)));
166 }
167
168 void
169 deallocate(_Tp* __p, size_t __n) noexcept
170 __attribute__((__nonnull__))
171 { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
172
173#ifdef __glibcxx_polymorphic_allocator // >= C++20
174 [[nodiscard]] void*
175 allocate_bytes(size_t __nbytes,
176 size_t __alignment = alignof(max_align_t))
177 { return _M_resource->allocate(__nbytes, __alignment); }
178
179 void
180 deallocate_bytes(void* __p, size_t __nbytes,
181 size_t __alignment = alignof(max_align_t))
182 { _M_resource->deallocate(__p, __nbytes, __alignment); }
183
184 template<typename _Up>
185 [[nodiscard]] _Up*
186 allocate_object(size_t __n = 1)
187 {
188 if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n)
189 std::__throw_bad_array_new_length();
190 return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
191 alignof(_Up)));
192 }
193
194 template<typename _Up>
195 void
196 deallocate_object(_Up* __p, size_t __n = 1)
197 { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
198
199 template<typename _Up, typename... _CtorArgs>
200 [[nodiscard]] _Up*
201 new_object(_CtorArgs&&... __ctor_args)
202 {
203 _Up* __p = allocate_object<_Up>();
204 __try
205 {
206 construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
207 }
208 __catch (...)
209 {
210 deallocate_object(__p);
211 __throw_exception_again;
212 }
213 return __p;
214 }
215
216 template<typename _Up>
217 void
218 delete_object(_Up* __p)
219 {
220 __p->~_Up();
221 deallocate_object(__p);
222 }
223#endif // C++20
224
225#if ! __glibcxx_make_obj_using_allocator // >= C++20
226 template<typename _Tp1, typename... _Args>
227 __attribute__((__nonnull__))
228 typename __not_pair<_Tp1>::type
229 construct(_Tp1* __p, _Args&&... __args)
230 {
231 // _GLIBCXX_RESOLVE_LIB_DEFECTS
232 // 2969. polymorphic_allocator::construct() shouldn't pass resource()
233 using __use_tag
234 = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
235 if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
236 ::new(__p) _Tp1(std::forward<_Args>(__args)...);
237 else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
238 ::new(__p) _Tp1(allocator_arg, *this,
239 std::forward<_Args>(__args)...);
240 else
241 ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
242 }
243
244 template<typename _Tp1, typename _Tp2,
245 typename... _Args1, typename... _Args2>
246 __attribute__((__nonnull__))
247 void
250 {
251 auto __x_tag =
252 __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
253 auto __y_tag =
254 __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
255 index_sequence_for<_Args1...> __x_i;
256 index_sequence_for<_Args2...> __y_i;
257
259 _S_construct_p(__x_tag, __x_i, __x),
260 _S_construct_p(__y_tag, __y_i, __y));
261 }
262
263 template<typename _Tp1, typename _Tp2>
264 __attribute__((__nonnull__))
265 void
266 construct(pair<_Tp1, _Tp2>* __p)
267 { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
268
269 template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
270 __attribute__((__nonnull__))
271 void
272 construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
273 {
274 this->construct(__p, piecewise_construct,
277 }
278
279 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
280 __attribute__((__nonnull__))
281 void
282 construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
283 {
284 this->construct(__p, piecewise_construct,
287 }
288
289 template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
290 __attribute__((__nonnull__))
291 void
292 construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
293 {
294 this->construct(__p, piecewise_construct,
297 }
298#else // make_obj_using_allocator
299 template<typename _Tp1, typename... _Args>
300 __attribute__((__nonnull__))
301 void
302 construct(_Tp1* __p, _Args&&... __args)
303 {
304 std::uninitialized_construct_using_allocator(__p, *this,
305 std::forward<_Args>(__args)...);
306 }
307#endif
308
309 template<typename _Up>
310 __attribute__((__nonnull__))
311 void
312 destroy(_Up* __p)
313 { __p->~_Up(); }
314
315 polymorphic_allocator
316 select_on_container_copy_construction() const noexcept
317 { return polymorphic_allocator(); }
318
320 resource() const noexcept
321 __attribute__((__returns_nonnull__))
322 { return _M_resource; }
323
324 // _GLIBCXX_RESOLVE_LIB_DEFECTS
325 // 3683. operator== for polymorphic_allocator cannot deduce template arg
326 [[nodiscard]]
327 friend bool
328 operator==(const polymorphic_allocator& __a,
329 const polymorphic_allocator& __b) noexcept
330 { return *__a.resource() == *__b.resource(); }
331
332#if __cpp_impl_three_way_comparison < 201907L
333 [[nodiscard]]
334 friend bool
335 operator!=(const polymorphic_allocator& __a,
336 const polymorphic_allocator& __b) noexcept
337 { return !(__a == __b); }
338#endif
339
340 private:
341#if ! __glibcxx_make_obj_using_allocator // >= C++20
342 using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
343 using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
344
345 template<typename _Ind, typename... _Args>
346 static tuple<_Args&&...>
347 _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
348 { return std::move(__t); }
349
350 template<size_t... _Ind, typename... _Args>
351 static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
352 _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
353 tuple<_Args...>& __t)
354 {
355 return {
356 allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
357 };
358 }
359
360 template<size_t... _Ind, typename... _Args>
361 static tuple<_Args&&..., polymorphic_allocator>
362 _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
363 tuple<_Args...>& __t)
364 { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
365#endif
366
367 memory_resource* _M_resource;
368 };
369
370 template<typename _Tp1, typename _Tp2>
371 [[nodiscard]]
372 inline bool
373 operator==(const polymorphic_allocator<_Tp1>& __a,
374 const polymorphic_allocator<_Tp2>& __b) noexcept
375 { return *__a.resource() == *__b.resource(); }
376
377#if __cpp_impl_three_way_comparison < 201907L
378 template<typename _Tp1, typename _Tp2>
379 [[nodiscard]]
380 inline bool
381 operator!=(const polymorphic_allocator<_Tp1>& __a,
382 const polymorphic_allocator<_Tp2>& __b) noexcept
383 { return !(__a == __b); }
384#endif
385
386} // namespace pmr
387
388 template<typename _Alloc> struct allocator_traits;
389
390 /// Partial specialization for `std::pmr::polymorphic_allocator`
391 /**
392 * @ingroup pmr
393 * @headerfile memory_resource
394 * @since C++17
395 */
396 template<typename _Tp>
397 struct allocator_traits<pmr::polymorphic_allocator<_Tp>>
398 {
399 /// The allocator type
401
402 /// The allocated type
403 using value_type = _Tp;
404
405 /// The allocator's pointer type.
406 using pointer = _Tp*;
407
408 /// The allocator's const pointer type.
409 using const_pointer = const _Tp*;
410
411 /// The allocator's void pointer type.
412 using void_pointer = void*;
413
414 /// The allocator's const void pointer type.
415 using const_void_pointer = const void*;
416
417 /// The allocator's difference type
418 using difference_type = std::ptrdiff_t;
419
420 /// The allocator's size type
421 using size_type = std::size_t;
422
423 /** @{
424 * A `polymorphic_allocator` does not propagate when a
425 * container is copied, moved, or swapped.
426 */
430
431 static allocator_type
434 /// @}
435
436 /// Whether all instances of the allocator type compare equal.
438
439 template<typename _Up>
440 using rebind_alloc = pmr::polymorphic_allocator<_Up>;
441
442 template<typename _Up>
444
445 /**
446 * @brief Allocate memory.
447 * @param __a An allocator.
448 * @param __n The number of objects to allocate space for.
449 *
450 * Calls `a.allocate(n)`.
451 */
452 [[nodiscard]] static pointer
454 { return __a.allocate(__n); }
455
456 /**
457 * @brief Allocate memory.
458 * @param __a An allocator.
459 * @param __n The number of objects to allocate space for.
460 * @return Memory of suitable size and alignment for `n` objects
461 * of type `value_type`.
462 *
463 * The third parameter is ignored..
464 *
465 * Returns `a.allocate(n)`.
466 */
467 [[nodiscard]] static pointer
469 { return __a.allocate(__n); }
470
471 /**
472 * @brief Deallocate memory.
473 * @param __a An allocator.
474 * @param __p Pointer to the memory to deallocate.
475 * @param __n The number of objects space was allocated for.
476 *
477 * Calls `a.deallocate(p, n)`.
478 */
479 static void
481 { __a.deallocate(__p, __n); }
482
483 /**
484 * @brief Construct an object of type `_Up`
485 * @param __a An allocator.
486 * @param __p Pointer to memory of suitable size and alignment for
487 * an object of type `_Up`.
488 * @param __args Constructor arguments.
489 *
490 * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
491 * in C++11, C++14 and C++17. Changed in C++20 to call
492 * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
493 */
494 template<typename _Up, typename... _Args>
495 static void
496 construct(allocator_type& __a, _Up* __p, _Args&&... __args)
497 { __a.construct(__p, std::forward<_Args>(__args)...); }
498
499 /**
500 * @brief Destroy an object of type `_Up`
501 * @param __a An allocator.
502 * @param __p Pointer to the object to destroy
503 *
504 * Calls `p->_Up()`.
505 */
506 template<typename _Up>
507 static _GLIBCXX20_CONSTEXPR void
510 { __p->~_Up(); }
511
512 /**
513 * @brief The maximum supported allocation size
514 * @return `numeric_limits<size_t>::max() / sizeof(value_type)`
515 */
516 static _GLIBCXX20_CONSTEXPR size_type
517 max_size(const allocator_type&) noexcept
518 { return size_t(-1) / sizeof(value_type); }
519 };
520
521_GLIBCXX_END_NAMESPACE_VERSION
522} // namespace std
523
524#endif // C++17
525#endif // _GLIBCXX_MEMORY_RESOURCE_H
memory_resource * get_default_resource() noexcept
Get the current default memory resource pointer.
__bool_constant< false > false_type
The type used as a compile-time boolean with false value.
Definition type_traits:119
pair(_T1, _T2) -> pair< _T1, _T2 >
Two pairs are equal iff their members are equal.
constexpr tuple< _Elements &&... > forward_as_tuple(_Elements &&... __args) noexcept
Create a tuple of lvalue or rvalue references to the arguments.
Definition tuple:2680
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
constexpr piecewise_construct_t piecewise_construct
Tag for piecewise construction of std::pair objects.
Definition stl_pair.h:82
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
ISO C++ entities toplevel namespace is std.
integer_sequence< size_t, _Idx... > index_sequence
Alias template index_sequence.
Definition utility.h:162
make_index_sequence< sizeof...(_Types)> index_sequence_for
Alias template index_sequence_for.
Definition utility.h:170
Primary class template, tuple.
Definition tuple:834
is_nothrow_destructible
Definition type_traits:1127
Uniform interface to all allocator types.
_Alloc allocator_type
The allocator type.
Class memory_resource
Class template polymorphic_allocator.
static void construct(allocator_type &__a, _Up *__p, _Args &&... __args)
Construct an object of type _Up
std::ptrdiff_t difference_type
The allocator's difference type.
static void deallocate(allocator_type &__a, pointer __p, size_type __n)
Deallocate memory.
static constexpr void destroy(allocator_type &, _Up *__p) noexcept(is_nothrow_destructible< _Up >::value)
Destroy an object of type _Up
static constexpr size_type max_size(const allocator_type &) noexcept
The maximum supported allocation size.
static pointer allocate(allocator_type &__a, size_type __n)
Allocate memory.
const _Tp * const_pointer
The allocator's const pointer type.
static pointer allocate(allocator_type &__a, size_type __n, const_void_pointer)
Allocate memory.
const void * const_void_pointer
The allocator's const void pointer type.
static allocator_type select_on_container_copy_construction(const allocator_type &) noexcept
void * void_pointer
The allocator's void pointer type.
false_type is_always_equal
Whether all instances of the allocator type compare equal.
pmr::polymorphic_allocator< _Tp > allocator_type
The allocator type.
Struct holding two objects of arbitrary type.
Definition stl_pair.h:304
_T1 first
The first member.
Definition stl_pair.h:308
_T2 second
The second member.
Definition stl_pair.h:309
Tag type for piecewise construction of std::pair objects.
Definition stl_pair.h:79