BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslma_memoryresource.h
Go to the documentation of this file.
1/// @file bslma_memoryresource.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslma_memoryresource.h -*-C++-*-
8#ifndef INCLUDED_BSLMA_MEMORYRESOURCE
9#define INCLUDED_BSLMA_MEMORYRESOURCE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslma_memoryresource bslma_memoryresource
15/// @brief Provide a pure abstract interface for memory-allocation mechanisms.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslma
19/// @{
20/// @addtogroup bslma_memoryresource
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslma_memoryresource-purpose"> Purpose</a>
25/// * <a href="#bslma_memoryresource-classes"> Classes </a>
26/// * <a href="#bslma_memoryresource-description"> Description </a>
27/// * <a href="#bslma_memoryresource-thread-safety"> Thread Safety </a>
28/// * <a href="#bslma_memoryresource-usage"> Usage </a>
29/// * <a href="#bslma_memoryresource-example-1-a-counting-memory-resource"> Example 1: a counting memory resource </a>
30/// * <a href="#bslma_memoryresource-example-2-a-class-that-allocates-memory"> Example 2: A class that allocates memory </a>
31///
32/// # Purpose {#bslma_memoryresource-purpose}
33/// Provide a pure abstract interface for memory-allocation mechanisms.
34///
35/// # Classes {#bslma_memoryresource-classes}
36///
37/// - bsl::memory_resource: protocol class for memory allocation and deallocation
38///
39/// **Canonical header:** bsl_memory_resource.h
40///
41/// @see bslma_allocator, bslma_polymorphicallocator
42///
43/// # Description {#bslma_memoryresource-description}
44/// This component is for internal use only. Please include
45/// `<bsl_memory_resource.h>` instead and use `bsl::memory_resource` directly.
46///
47/// This component provides a protocol (pure abstract interface) class,
48/// `bsl::memory_resource`, comprising member functions for allocating and
49/// deallocating memory. The `bsl::memory_resource` interface is identical to
50/// that of `std::pmr::memory_resource` from the C++17 Standard Library; in
51/// fact, the former type is an alias for the latter type when using a C++17 or
52/// later library supplied by the platform.
53///
54/// A concrete class derived from `bsl::memory_resource` might use pooling or
55/// other mechanisms that improve on `new` and `delete` in some way, such as
56/// speeding up the program or providing instrumentation for debugging or
57/// security. A `memory_resource` thus provides a customizable alterantive to
58/// using raw calls to `new` and `delete`.
59///
60/// An object, `Obj`, holding a base-class pointer, `d_resource_p`, of type
61/// `bsl::memory_resource *` would allocate and deallocate memory by calling the
62/// resource's `allocate` and `deallocate` member functions (through
63/// `d_resource_p`), which subsequently invoke the respective virtual functions,
64/// `do_allocate` and `do_deallocate`. A client can thus customize the memory
65/// allocation mechanism used by `Obj` by providing it with an appropriate
66/// concrete resource whose class overrides `do_allocate` and `do_deallocate`.
67///
68/// ## Thread Safety {#bslma_memoryresource-thread-safety}
69///
70///
71/// Unless otherwise documented, a single memory resource object is not safe for
72/// concurrent access by multiple threads. Classes derived from
73/// `bsl::memory_resource` that are specifically designed for concurrent access
74/// must be documented as such. Unless specifically documented otherwise,
75/// separate objects of classes derived from `bsl::memory_resource` may safely
76/// be used in separate threads.
77///
78/// Note that some memory resources delegate to other memory resource objects.
79/// When used in a concurrent context, the thread safety of the entire chain
80/// must be considered.
81///
82/// ## Usage {#bslma_memoryresource-usage}
83///
84///
85/// The `bsl::memory_resource` protocol provided in this component defines a
86/// bilateral contract between suppliers and consumers of raw memory. The
87/// following subsections illustrate (1) implementation of a concrete resource
88/// derived from the abstract `bsl::memory_resource` base class and (2) use of a
89/// `bsl::memory_resource`.
90///
91/// ### Example 1: a counting memory resource {#bslma_memoryresource-example-1-a-counting-memory-resource}
92///
93///
94/// In this example, we derive a concrete `CountingResource` class from
95/// `bsl::memory_resource`, overriding and providing concrete implementations
96/// for all of the virtual functions declared in the base class. This resource
97/// keeps track of the number of blocks of memory that were allocated from the
98/// resource but not yet returned to the resource.
99///
100/// First, we define the `CountingResource` class with a single private data
101/// member to keep track of the number of blocks outstanding. We don't want
102/// this type to be copyable, so we disable copying here, too.
103/// @code
104/// #include <bslmf_movableref.h>
105/// #include <bsls_assert.h>
106/// #include <bsls_keyword.h>
107/// #include <bsls_exceptionutil.h>
108/// #include <stdint.h> // 'uintptr_t'
109///
110/// class CountingResource : public bsl::memory_resource {
111///
112/// // DATA
113/// int d_blocksOutstanding;
114///
115/// CountingResource(const CountingResource&) BSLS_KEYWORD_DELETED;
116/// CountingResource& operator=(const CountingResource&)
117/// BSLS_KEYWORD_DELETED;
118/// @endcode
119/// Next, we declare the protected virtual functions that override the
120/// base-class virtual functions:
121/// @code
122/// protected:
123/// // PROTECTED MANIPULATORS
124/// void* do_allocate(std::size_t bytes,
125/// std::size_t alignment) BSLS_KEYWORD_OVERRIDE;
126/// void do_deallocate(void* p, std::size_t bytes,
127/// std::size_t alignment) BSLS_KEYWORD_OVERRIDE;
128///
129/// // PROTECTED ACCESSORS
130/// bool do_is_equal(const bsl::memory_resource& other) const
131/// BSLS_KEYWORD_NOEXCEPT BSLS_KEYWORD_OVERRIDE;
132/// @endcode
133/// Now we can declare the public interface, comprising the default constructor,
134/// the destructor, and an accessor to return the current block count; all other
135/// public members are inherited from the base class:
136/// @code
137/// public:
138/// // CREATORS
139/// CountingResource() : d_blocksOutstanding(0) { }
140/// ~CountingResource() BSLS_KEYWORD_OVERRIDE;
141///
142/// // ACCESSORS
143/// int blocksOutstanding() const { return d_blocksOutstanding; }
144/// };
145/// @endcode
146/// Next, we implement the `do_allocate` method to allocate memory using
147/// `operator new`, then increment the block counter. We cannot, in C++11,
148/// force `operator new` to return memory that is more than maximally aligned,
149/// so we throw an exception if the specified `alignment` is not met; other
150/// resources can use the `alignment` argument more productively.
151/// @code
152/// void *CountingResource::do_allocate(std::size_t bytes,
153/// std::size_t alignment)
154/// {
155/// void *ret = ::operator new(bytes);
156/// if (uintptr_t(ret) & (alignment - 1)) {
157/// ::operator delete(ret);
158/// BSLS_THROW(this); // Alignment failed
159/// }
160/// ++d_blocksOutstanding;
161/// return ret;
162/// }
163/// @endcode
164/// Next, we implement `do_deallocate`, which returns the memory referenced by
165/// `p` to the heap and decrements the block counter. The `bytes` and
166/// `alignment` arguments are ignored:
167/// @code
168/// void CountingResource::do_deallocate(void* p, std::size_t, std::size_t)
169/// {
170/// ::operator delete(p);
171/// --d_blocksOutstanding;
172/// }
173/// @endcode
174/// Next, we implement `do_is_equal`, which determines if the specified `other`
175/// resource is equal to this one. For this and most other resource types,
176/// `do_is_equal` returns `true` if and only if the two resources are the same
177/// object:
178/// @code
179/// bool CountingResource::do_is_equal(const bsl::memory_resource& other) const
180/// BSLS_KEYWORD_NOEXCEPT
181/// {
182/// return this == &other;
183/// }
184/// @endcode
185/// Next, we implement the destructor, which simply asserts that the block count
186/// is zero upon destruction:
187/// @code
188/// CountingResource::~CountingResource()
189/// {
190/// BSLS_ASSERT(0 == d_blocksOutstanding);
191/// }
192/// @endcode
193/// Finally, we construct an object of `CountingResource` and verify that
194/// allocation, deallocation, and equality testing work as expected.
195/// @code
196/// int main()
197/// {
198/// CountingResource obj;
199/// assert(0 == obj.blocksOutstanding());
200///
201/// void *p = obj.allocate(16, 4);
202/// assert(p);
203/// assert(0 == (uintptr_t(p) & 3));
204/// assert(1 == obj.blocksOutstanding());
205///
206/// obj.deallocate(p, 16, 4);
207/// assert(0 == obj.blocksOutstanding());
208///
209/// CountingResource obj2;
210/// assert(obj == obj);
211/// assert(obj != obj2);
212/// }
213/// @endcode
214///
215/// ### Example 2: A class that allocates memory {#bslma_memoryresource-example-2-a-class-that-allocates-memory}
216///
217///
218/// In this example, we define a class template, `Holder<TYPE>`, that holds a
219/// single instance of `TYPE` on the heap. `Holder` is designed such that its
220/// memory use can be customized by supplying an appropriate memory resource. A
221/// holder object can be empty and it can be move-constructed even if `TYPE` is
222/// not movable. In addition, the footprint of a `Holder` object is the same
223/// (typically the size of 2 pointers), regardless of the size of `TYPE`.
224///
225/// First, we define a simple class template modeled after the C++17 standard
226/// library `std::pmr::polymorphic_allocator` template, which is a thin wrapper
227/// around a `memory_resource` pointer. By wrapping the pointer in a class, we
228/// avoid some the problems of raw pointers such as accidental use of a null
229/// pointer:
230/// @code
231/// #include <bsls_alignmentfromtype.h>
232///
233/// template <class TYPE>
234/// class PolymorphicAllocator {
235///
236/// // DATA
237/// bsl::memory_resource *d_resource_p;
238///
239/// public:
240/// // CREATORS
241/// PolymorphicAllocator(bsl::memory_resource *r); // IMPLICIT
242///
243/// // MANIPULATORS
244/// TYPE *allocate(std::size_t n);
245/// void deallocate(TYPE *p, size_t n);
246///
247/// // ACCESSORS
248/// bsl::memory_resource *resource() const { return d_resource_p; }
249/// };
250/// @endcode
251/// Next, we implement the constructor for `PolymorphicAllocator`, which stores
252/// the pointer argument and defensively checks that it is not null:
253/// @code
254/// template <class TYPE>
255/// PolymorphicAllocator<TYPE>::PolymorphicAllocator(bsl::memory_resource *r)
256/// : d_resource_p(r)
257/// {
258/// BSLS_ASSERT(0 != r);
259/// }
260/// @endcode
261/// Next, we implement the allocation and deallocation functions by forwarding
262/// to the corresponding function of the memory resource. Note that the size
263/// and alignment of `TYPE` are used to compute the appropriate number of bytes
264/// and alignment to request from the memory resource:
265/// @code
266/// template <class TYPE>
267/// TYPE *PolymorphicAllocator<TYPE>::allocate(std::size_t n)
268/// {
269/// void *p = d_resource_p->allocate(n * sizeof(TYPE),
270/// bsls::AlignmentFromType<TYPE>::VALUE);
271/// return static_cast<TYPE *>(p);
272/// }
273///
274/// template <class TYPE>
275/// void PolymorphicAllocator<TYPE>::deallocate(TYPE *p, std::size_t n)
276/// {
277/// d_resource_p->deallocate(p, n * sizeof(TYPE),
278/// bsls::AlignmentFromType<TYPE>::VALUE);
279/// }
280/// @endcode
281/// Now we define our actual `Holder` template with with data members to hold
282/// the memory allocator and a pointer to the contained object:
283/// @code
284/// template <class TYPE>
285/// class Holder {
286/// PolymorphicAllocator<TYPE> d_allocator;
287/// TYPE *d_data_p;
288/// @endcode
289/// Next, we declare the constructors. Following the pattern for
290/// allocator-aware types used in BDE, the public interface contains an
291/// `allocator_type` typedef that can be passed to each constructor.
292/// Typically, the allocator constructor argument would be optional, but,
293/// because our `PolymorphicAllocator` has no default constructor (unlike the
294/// `std::pmr::polymorphic_allocator`), the allocator is *required* for all
295/// constructors except the move constructor:
296/// @code
297/// public:
298/// // TYPES
299/// typedef PolymorphicAllocator<TYPE> allocator_type;
300///
301/// // CREATORS
302/// explicit Holder(const allocator_type& allocator);
303/// Holder(const TYPE& value, const allocator_type& allocator);
304/// Holder(const Holder& other, const allocator_type& allocator);
305/// Holder(bslmf::MovableRef<Holder> other); // IMPLICIT
306/// Holder(bslmf::MovableRef<Holder> other,
307/// const allocator_type& allocator);
308/// ~Holder();
309/// @endcode
310/// Next, we declare the manipulators and accessors, allowing a `Holder` to be
311/// assigned and giving a client access to its value and allocator:
312/// @code
313/// // MANIPULATORS
314/// Holder& operator=(const Holder& rhs);
315/// Holder& operator=(bslmf::MovableRef<Holder> rhs);
316/// TYPE& value() { return *d_data_p; }
317///
318/// // ACCESSORS
319/// bool isEmpty() const { return 0 == d_data_p; }
320/// const TYPE& value() const { return *d_data_p; }
321/// allocator_type get_allocator() const { return d_allocator; }
322/// };
323/// @endcode
324/// Next, we'll implement the first constructor, which creates an empty object;
325/// its only job is to store the allocator:
326/// @code
327/// template <class TYPE>
328/// Holder<TYPE>::Holder(const allocator_type& allocator)
329/// : d_allocator(allocator)
330/// , d_data_p(0)
331/// {
332/// }
333/// @endcode
334/// Next, we'll implement the second constructor, which allocates memory and
335/// constructs an object in it. The `try`/`catch` block is needed to free the
336/// memory in case the constructor for `TYPE` throws and exception. An
337/// alternative implementation would use an RAII object to automatically free
338/// the memory in the case of an exception (see @ref bslma_deallocatorproctor ):
339/// @code
340/// template <class TYPE>
341/// Holder<TYPE>::Holder(const TYPE& value, const allocator_type& allocator)
342/// : d_allocator(allocator)
343/// , d_data_p(0)
344/// {
345/// d_data_p = d_allocator.allocate(1);
346/// BSLS_TRY {
347/// ::new(d_data_p) TYPE(value);
348/// }
349/// BSLS_CATCH(...) {
350/// d_allocator.deallocate(d_data_p, 1);
351/// BSLS_RETHROW;
352/// }
353/// }
354/// @endcode
355/// Next, we'll implement a destructor that deletes the value object and
356/// deallocates the allocated memory:
357/// @code
358/// template <class TYPE>
359/// Holder<TYPE>::~Holder()
360/// {
361/// if (! isEmpty()) {
362/// d_data_p->~TYPE(); // Destroy object.
363/// d_allocator.deallocate(d_data_p, 1); // Deallocate memory.
364/// }
365/// }
366/// @endcode
367/// Finally, we've implemented enough of `Holder` to demonstrate its use.
368/// Below, we pass the `CountingResource` from Example 1 to the constructors
369/// several `Holder` objects. Each non-empty `Holder` allocates one block of
370/// memory, which is reflected in the outstanding block count. Note that the
371/// address of the resource can be passed directly to the constructors because
372/// `PolymorphicAllocator` is implicitly convertible from 'bsl::memory_resource
373/// *':
374/// @code
375/// int main()
376/// {
377/// CountingResource rsrc;
378///
379/// {
380/// Holder<int> h1(&rsrc); // Empty resource
381/// assert(h1.isEmpty());
382/// assert(0 == rsrc.blocksOutstanding());
383///
384/// Holder<int> h2(2, &rsrc);
385/// assert(! h2.isEmpty());
386/// assert(1 == rsrc.blocksOutstanding());
387///
388/// Holder<double> h3(3.0, &rsrc);
389/// assert(! h3.isEmpty());
390/// assert(2 == rsrc.blocksOutstanding());
391/// }
392///
393/// assert(0 == rsrc.blocksOutstanding()); // Destructors freed memory
394/// }
395/// @endcode
396/// @}
397/** @} */
398/** @} */
399
400/** @addtogroup bsl
401 * @{
402 */
403/** @addtogroup bslma
404 * @{
405 */
406/** @addtogroup bslma_memoryresource
407 * @{
408 */
409
410
411#include <bslscm_version.h>
412
413#include <bsls_alignmentutil.h>
414#include <bsls_annotation.h>
415#include <bsls_keyword.h>
416#include <bsls_libraryfeatures.h>
417
418#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
419// Use `memory_resource` from native C++17 library, if available.
420
421# include <memory_resource>
422
423namespace bsl {
424
425using std::pmr::memory_resource;
426
427} // close namespace bsl
428
429#else // If C++17 library is not available
430
431namespace bsl {
432
433 // =====================
434 // Class memory_resource
435 // =====================
436
437// A protocol (pure abstract interface) class, comprising member functions
438// for allocating and deallocating memory. This class is a pre-C++17
439// implementation of `std::pmr::memory_resource` from the C++17 Standard
440// Library.
442
443 // PRIVATE CONSTANTS
444 enum {
445 k_MAX_ALIGN = BloombergLP::bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT
446 };
447
448 public:
449 // CREATORS
450
451 /// Create this object. Has no effect other than to begin its lifetime.
452 memory_resource() BSLS_KEYWORD_DEFAULT;
453 memory_resource(const memory_resource&) BSLS_KEYWORD_DEFAULT;
454
455 /// Destroy this object. Has no effect other than to end its lifetime.
456 virtual ~memory_resource();
457
458 // MANIPULATORS
459
460 /// Return a modifiable reference to this object.
462 BSLS_KEYWORD_DEFAULT;
463
464 /// Return the (non-null) address of a block of memory suitable for
465 /// holding an object having at least the specified `bytes` and
466 /// `alignment`. If this memory resource is unable to fulfill the
467 /// request, i.e., because `bytes` or `alignment` is too large, then
468 /// throw @ref bad_alloc or other suitable exception. The behavior is
469 /// undefined unless `alignment` is a power of two. Note that this
470 /// function calls the derived-class implementation of `do_allocate`.
472 void *allocate(size_t bytes, size_t alignment = k_MAX_ALIGN);
473
474 /// Deallocate the block of memory at the specified address `p` and
475 /// having the specified `bytes` and `alignment` by returning it to the
476 /// derived-class memory resource. The behavior is undefined unless `p`
477 /// was allocated from this resource using the same size and alignment
478 /// and has not yet been deallocated. Note that this function calls the
479 /// derived-class implementation of `do_deallocate`.
480 void deallocate(void *p, size_t bytes, size_t alignment = k_MAX_ALIGN);
481
482 // ACCESSORS
483
484 /// Return `true` if memory allocated from this resource can be
485 /// deallocated from the specified `other` resource and vice-versa;
486 /// otherwise return `false`. Note that this function calls the
487 /// derived-class implementation of `do_is_equal`.
488 bool is_equal(const memory_resource& other) const BSLS_KEYWORD_NOEXCEPT;
489
490 private:
491 // PRIVATE MANIPULATORS
492
493 /// Return a block of memory, allocated from the derived-class resource,
494 /// suitable for holding an object having at least the specified `bytes`
495 /// and `alignment`. The behavior is undefined unless `alignment` is a
496 /// power of two.
497 virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
498
499 /// Deallocate the block of memory at the specified address `p` and
500 /// having the specified `bytes` and `alignment` by returning it to the
501 /// derived-class memory resource. The behavior is undefined unless `p`
502 /// was allocated from this resource using the same size and alignment
503 /// and has not yet been deallocated.
504 virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
505
506 // PRIVATE ACCESSORS
507
508 /// Return `true` if memory allocated from this resource can be
509 /// deallocated from the specified `other` resource and vice-versa;
510 /// otherwise return `false`.
511 virtual bool do_is_equal(const memory_resource& other) const
513};
514
515// FREE OPERATORS
516
517/// Return `true` if memory allocated from the specified `a` resource can be
518/// deallocated from the specified `b` resource; otherwise return `false`.
519bool operator==(const memory_resource& a, const memory_resource& b);
520
521/// Return `true` if memory allocated from the specified `a` resource cannot
522/// be deallocated from the specified `b` resource; otherwise return
523/// `false`.
524bool operator!=(const memory_resource& a, const memory_resource& b);
525
526// ============================================================================
527// INLINE FUNCTION IMPLEMENTATIONS
528// ============================================================================
529
530// CREATORS
531inline
533{
534 // Implementation note: because `memory_resource` is a pure abstract class
535 // with a trivial constructor, the virtual destructor can be inlined
536 // without forcing the implementation to generate a vtbl for the class.
537}
538
539// MANIPULATORS
540inline
541void *memory_resource::allocate(size_t bytes, size_t alignment)
542{
543 return do_allocate(bytes, alignment);
544}
545
546inline
547void memory_resource::deallocate(void *p, size_t bytes, size_t alignment)
548{
549 do_deallocate(p, bytes, alignment);
550}
551
552// ACCESSORS
553inline
556{
557 return do_is_equal(other);
558}
559
560} // close namespace bsl
561
562
563// FREE OPERATORS
564
565inline
566bool bsl::operator==(const bsl::memory_resource& a,
567 const bsl::memory_resource& b)
568{
569 return a.is_equal(b);
570}
571
572inline
574 const bsl::memory_resource& b)
575{
576 return ! a.is_equal(b);
577}
578
579#endif // ! defined(BSLS_LIBRARYFEATURES_HAS_CPP17_PMR)
580
581#endif // ! defined(INCLUDED_BSLMA_MEMORYRESOURCE)
582
583// ----------------------------------------------------------------------------
584// Copyright 2022 Bloomberg Finance L.P.
585//
586// Licensed under the Apache License, Version 2.0 (the "License");
587// you may not use this file except in compliance with the License.
588// You may obtain a copy of the License at
589//
590// http://www.apache.org/licenses/LICENSE-2.0
591//
592// Unless required by applicable law or agreed to in writing, software
593// distributed under the License is distributed on an "AS IS" BASIS,
594// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
595// See the License for the specific language governing permissions and
596// limitations under the License.
597// ----------------------------- END-OF-FILE ----------------------------------
598
599/** @} */
600/** @} */
601/** @} */
Definition bslma_memoryresource.h:441
bool is_equal(const memory_resource &other) const BSLS_KEYWORD_NOEXCEPT
Definition bslma_memoryresource.h:554
BSLS_ANNOTATION_NODISCARD void * allocate(size_t bytes, size_t alignment=k_MAX_ALIGN)
Definition bslma_memoryresource.h:541
void deallocate(void *p, size_t bytes, size_t alignment=k_MAX_ALIGN)
Definition bslma_memoryresource.h:547
memory_resource() BSLS_KEYWORD_DEFAULT
Create this object. Has no effect other than to begin its lifetime.
#define BSLS_ANNOTATION_NODISCARD
Definition bsls_annotation.h:373
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:632
Definition bdlb_printmethods.h:283
bool operator!=(const memory_resource &a, const memory_resource &b)