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