BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslma_deallocatebytesproctor.h
Go to the documentation of this file.
1/// @file bslma_deallocatebytesproctor.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslma_deallocatebytesproctor.h -*-C++-*-
8#ifndef INCLUDED_BSLMA_DEALLOCATEBYTESPROCTOR
9#define INCLUDED_BSLMA_DEALLOCATEBYTESPROCTOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslma_deallocatebytesproctor bslma_deallocatebytesproctor
15/// @brief Provide a proctor to conditionally unwind memory block allocation.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslma
19/// @{
20/// @addtogroup bslma_deallocatebytesproctor
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslma_deallocatebytesproctor-purpose"> Purpose</a>
25/// * <a href="#bslma_deallocatebytesproctor-classes"> Classes </a>
26/// * <a href="#bslma_deallocatebytesproctor-description"> Description </a>
27/// * <a href="#bslma_deallocatebytesproctor-usage"> Usage </a>
28///
29/// # Purpose {#bslma_deallocatebytesproctor-purpose}
30/// Provide a proctor to conditionally unwind memory block allocation.
31///
32/// # Classes {#bslma_deallocatebytesproctor-classes}
33///
34/// - bslma::DeallocateBytesProctor: proctor to conditionally unwind allocation.
35///
36/// @see bslma_deallocateobjectproctor, bslma_deleteobjectproctor
37///
38/// # Description {#bslma_deallocatebytesproctor-description}
39/// This component provides a proctor class template,
40/// `bslma::DeallocateBytesProctor`, that conditionally reverses the effect of
41/// `bslma::AllocatorUtil::allocateBytes(a, n, align)` or `a->allocate(n)`,
42/// where `a` is a memory resource or pool that allocates, `n` is the number of
43/// bytes to allocate, and align is the desired alignment. Upon destruction,
44/// this proctor deallocates the block from the specified allocator or pool
45/// without calling any destructors. The proctor's constructor takes the same
46/// arguments as `bslma::AllocatorUtil::deallocateBytes`, making it
47/// straightforward to allocate an object using `allocateBytes` and protect it
48/// using `DeallocateBytesProctor`.
49///
50/// As with all proctors, this class is used to automatically reclaim a resource
51/// in the event that a function ends prematurely, e.g., via an exception.
52/// After allocating a block of memory, an exception-safe function
53/// would create a `DeallocateBytesProctor` to manage the new memory block.
54/// If the operation completes successfully, the code calls the proctor's
55/// `release` method, which disengages the proctor. If, however, the function
56/// exits while the proctor is still engaged, the proctor's destructor will
57/// deallocate the managed memory block.
58///
59/// The `DeallocateBytesProctor` template has one template parameter: the
60/// `ALLOCATOR` type used to reclaim storage managed by the proctor. If
61/// `ALLOCATOR` is a non-pointer type, the proctor uses
62/// `bslma::AllocatorUtil::deallocateBytes(a, ptr, n, align)` to reclaim
63/// storage, where `a` is the allocator, `ptr` is the address of the managed
64/// memory block, `n` is the number of managed bytes, and `align` is an optional
65/// argument specifying the alignment of the block (max-aligned by default).
66/// Otherwise, if `ALLOCATOR` is a pointer type, the proctor reclaims memory by
67/// calling `a->deallocate(ptr)`. Instantiating `DeallocateBytesProctor` with a
68/// pointer-type `ALLOCATOR` is appropriate for classes derived from
69/// `bslma::Allocator` and for BDE-style pool types, i.e., classes for which
70/// `a->deallocate(ptr)` is well formed.
71///
72/// ## Usage {#bslma_deallocatebytesproctor-usage}
73///
74///
75///Example 1: Class having an owning pointer
76///- - - - - - - - - - - - - - - - - - - - -
77/// In this example, we create a class, `my_Manager`, having an owning pointer
78/// to an object of another class, `my_Data`. Because it owns the `my_Data`
79/// object, `my_Manager` is responsible for allocating, constructing,
80/// deallocating, and destroying it.
81///
82/// First, we define the `my_Data` class, which holds an integer value and
83/// counts how many times its constructor and destructor have been called. Its
84/// constructor will throw an exception if its integer argument equals the
85/// number of constructor calls before construction:
86/// @code
87/// #include <bslma_allocatorutil.h>
88/// #include <bslma_bslallocator.h>
89/// #include <bslma_testallocator.h>
90///
91/// class my_Data {
92///
93/// // DATA
94/// int d_value;
95///
96/// // CLASS DATA
97/// static int s_numConstructed;
98/// static int s_numDestroyed;
99///
100/// public:
101/// // CLASS METHODS
102/// static int numConstructed() { return s_numConstructed; }
103/// static int numDestroyed() { return s_numDestroyed; }
104///
105/// // CREATORS
106/// explicit my_Data(int v) : d_value(v)
107/// {
108/// if (v == s_numConstructed) throw s_numConstructed;
109/// ++s_numConstructed;
110/// }
111/// my_Data(const my_Data& original);
112/// ~my_Data() { ++s_numDestroyed; }
113/// };
114///
115/// int my_Data::s_numConstructed = 0;
116/// int my_Data::s_numDestroyed = 0;
117/// @endcode
118/// Next, we define `my_Manager` as an allocator-aware class holding a pointer
119/// to `my_Data` and maintaining its own count of constructor invocations:
120/// @code
121/// class my_Manager {
122///
123/// // DATA
124/// bsl::allocator<my_Data> d_allocator;
125/// my_Data *d_data_p;
126///
127/// // CLASS DATA
128/// static int s_numConstructed;
129///
130/// public:
131/// // TYPES
132/// typedef bsl::allocator<> allocator_type;
133///
134/// // CLASS METHODS
135/// static int numConstructed() { return s_numConstructed; }
136///
137/// // CREATORS
138/// explicit my_Manager(int v,
139/// const allocator_type& allocator = allocator_type());
140/// my_Manager(const my_Manager& original);
141/// ~my_Manager();
142///
143/// // ...
144/// };
145///
146/// int my_Manager::s_numConstructed = 0;
147/// @endcode
148/// Next, we define the constructor for `my_Manager`, which begins by allocating
149/// a `my_Data` object:
150/// @code
151/// my_Manager::my_Manager(int v, const allocator_type& allocator)
152/// : d_allocator(allocator), d_data_p(0)
153/// {
154/// d_data_p = static_cast<my_Data*>(
155/// bslma::AllocatorUtil::allocateBytes(allocator, sizeof(my_Data)));
156/// @endcode
157/// Then, the `my_Manager` constructor constructs the `my_Data` object in the
158/// allocated memory. However, as the constructor might throw, it first
159/// protects the data object with a `bslma::DeallocateBytesProctor`:
160/// @code
161/// bslma::DeallocateBytesProctor<allocator_type>
162/// proctor(d_allocator, d_data_p, sizeof(my_Data));
163/// bslma::ConstructionUtil::construct(d_data_p, d_allocator, v);
164/// @endcode
165/// Then, once the `construct` operation completes successfully, we can release
166/// the data object from the proctor. Only then do we increment the
167/// construction count, as the constructor is now complete:
168/// @code
169/// proctor.release();
170/// ++s_numConstructed;
171/// }
172/// @endcode
173/// Next, we define the `my_Manager` destructor, which destroys and deallocates
174/// its data object. Note that the arguments to `deallocateBytes` is identical
175/// to the constructor arguments to the `DeallocateBytesProctor`, above:
176/// @code
177/// my_Manager::~my_Manager()
178/// {
179/// d_data_p->~my_Data();
180/// bslma::AllocatorUtil::deallocateBytes(d_allocator, d_data_p,
181/// sizeof(my_Data));
182/// }
183/// @endcode
184/// Now, we use a `bslma::TestAllocator` to verify that, under normal (non
185/// exceptional) circumstances, constructing a `my_Manager` object will result
186/// in one block of memory being allocated and one invocation of the `my_Data`
187/// constructor:
188/// @code
189/// int main()
190/// {
191/// bslma::TestAllocator ta;
192///
193/// {
194/// my_Manager obj1(7, &ta);
195/// assert(1 == ta.numBlocksInUse());
196/// assert(1 == ta.numBlocksTotal());
197/// assert(1 == my_Manager::numConstructed());
198/// }
199/// assert(0 == ta.numBlocksInUse());
200/// assert(1 == ta.numBlocksTotal());
201/// assert(1 == my_Manager::numConstructed());
202/// @endcode
203/// Finally, when the `my_Data` constructor does throw, a block is allocated but
204/// we verify that the `my_Manager` constructor did not complete and that the
205/// block is automatically deallocated, resulting in no leaks:
206/// @code
207/// try {
208/// my_Manager obj2(1, &ta); // Will throw an exception
209/// assert(false && "Can't get here");
210/// }
211/// catch (int e) {
212/// assert(1 == e);
213/// assert(2 == ta.numBlocksTotal()); // A 2nd block was allocated...
214/// assert(0 == ta.numBlocksInUse()); // ...but was then deallocated
215/// assert(1 == my_Manager::numConstructed());
216/// }
217/// assert(1 == my_Manager::numConstructed());
218/// }
219/// @endcode
220/// @}
221/** @} */
222/** @} */
223
224/** @addtogroup bsl
225 * @{
226 */
227/** @addtogroup bslma
228 * @{
229 */
230/** @addtogroup bslma_deallocatebytesproctor
231 * @{
232 */
233
234#include <bslscm_version.h>
235
236#include <bslma_allocatorutil.h>
237
238#include <bslmf_assert.h>
240#include <bslmf_ispointer.h>
241#include <bslmf_issame.h>
242#include <bslmf_movableref.h>
243
244#include <bsls_alignmentutil.h>
245#include <bsls_keyword.h>
246
247#include <cstdlib> // std::size_t
248
249
250namespace bslma {
251
252// FORWARD DECLARATIONS
253template <class ALLOCATOR>
254struct DeallocateBytesProctor_PtrType;
255
256 // ======================================
257 // class template DeallocateBytesProctor
258 // ======================================
259
260/// This class implements a proctor that, unless its `release` method has
261/// previously been invoked, automatically deallocates a managed block of
262/// memory upon destruction by invoking the `deallocate` method of an
263/// allocator (or pool) of parameterized `ALLOCATOR` type supplied to it at
264/// construction. The managed memory block must have been provided by the
265/// supplied allocator (or pool); the allocator (or pool) must remain valid
266/// throughout the lifetime of the proctor object. If `ALLOCATOR` is a
267/// non-pointer type, it is assumed to be STL compatible; otherwise it is
268/// assumed have the same deallocation interface as `bslma::Allocator`.
269///
270/// See @ref bslma_deallocatebytesproctor
271template <class ALLOCATOR>
273
274 private:
275 // PRIVATE CONSTANTS
276 enum { k_MAX_ALIGNMENT = bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT };
277
278 // PRIVATE TYPES
281
282 // DATA
283 ALLOCATOR d_allocator; // allocator object (might be a pointer)
284 PtrType d_bytes_p; // managed block (null if disengaged)
285 std::size_t d_nbytes; // number of managed bytes
286 std::size_t d_alignment; // alignment of managed blocks
287
288 // PRIVATE MANIPULATORS
289
290 /// Deallocate the block at `d_bytes_p`. The first overload is selected
291 /// for non-pointer-type `ALLOCATOR` and invokes
292 /// `bslma::AllocatorUtil::deallocateBytes(d_allocator, d_bytes,
293 /// d_nbytes, d_alignment)`. The second overload is selected for a
294 /// pointer-type `ALLOCATOR` and invokes
295 /// `d_allocator->deallocate(d_object_p)`.
296 void doDeallocate(bsl::false_type);
297 void doDeallocate(bsl::true_type);
298
299 private:
300 // NOT IMPLEMENTED
304
305 public:
306 // CREATORS
307
308 /// Create a proctor to manage the specified `nbytes` bytes at the
309 /// specified `p` address, which have been allocated from the specified
310 /// `allocator`. Optionally specify the `alignment` used to allocate
311 /// the bytes. If `p` is null, then the created proctor is disengaged (manages no memory).
312 ///
313 /// \pre The behavior is undefined unless `p` is null
314 /// or was allocated from `allocator` with a size of `nbytes` and
315 /// alignment of `alignment`.
316 DeallocateBytesProctor(const ALLOCATOR& allocator,
317 PtrType p,
318 std::size_t nbytes,
319 std::size_t alignment = k_MAX_ALIGNMENT);
320
321 /// This move constructor creates a proctor managing the same block as
322 /// `original`. After the move, `original` is disengaged.
324
325 /// Deallocate the managed memory, if any, without invoking any other
326 /// destructors.
328
329 // MANIPULATORS
330
331 /// Disengage this allocator and return a pointer to the formerly
332 /// managed memory block.
333 PtrType release();
334
335 /// Release the managed memory and reset this proctor to manage the
336 /// specified `nbytes` bytes at the specified `p` address. Optionally
337 /// specify the `alignment` used to allocate `p`. If `p` is null, then
338 /// the proctor is disengaged (manages no memory).
339 ///
340 /// \pre The behavior is undefined unless `p` is null or was allocated with a size of
341 /// `nbytes` and alignment of `alignment` from the same allocator used to construct this proctor.
342 ///
343 /// \note Note that the previously managed block
344 /// is not deallocated.
345 void reset(PtrType p,
346 std::size_t nbytes,
347 std::size_t alignment = k_MAX_ALIGNMENT);
348
349 // ACCESSORS
350
351 /// Return the address of the currently managed memory block, if
352 /// engaged; otherwise return a null pointer.
353 PtrType ptr() const;
354};
355
356// ============================================================================
357// TEMPLATE AND INLINE FUNCTION IMPLEMENTATIONS
358// ============================================================================
359
360 // ----------------------------------------------
361 // struct template DeallocateBytesProctor_PtrType
362 // ----------------------------------------------
363
364/// This metafunction has a nested `type` that indicates the correct `void`
365/// pointer type to use to manage bytes allocated from an allocator having
366/// the specified `ALLOCATOR` template parameter type. This primary
367/// template yields the @ref void_pointer type specified by the
368/// `allocator_traits` for `ALLOCATOR`.
369template <class ALLOCATOR>
375
376/// This partial specialization is chosen when `ALLOCATOR` is a pointer type
377/// (i.e., `bslma::Allocator *` or a pointer to a pool class). It yields
378/// a `type` of `void *`.
379template <class ALLOCATOR>
381{
382
383 typedef void *type;
384};
385
386 // --------------------------------------
387 // class template DeallocateBytesProctor
388 // --------------------------------------
389
390// PRIVATE MANIPULATORS
391template <class ALLOCATOR>
392inline
394{
395 bslma::AllocatorUtil::deallocateBytes(d_allocator, d_bytes_p,
396 d_nbytes, d_alignment);
397}
398
399template <class ALLOCATOR>
400inline
401void DeallocateBytesProctor<ALLOCATOR>::doDeallocate(bsl::true_type)
402{
403 d_allocator->deallocate(d_bytes_p);
404}
405
406// CREATORS
407template <class ALLOCATOR>
408inline
410 const ALLOCATOR& allocator,
411 PtrType p,
412 std::size_t nbytes,
413 std::size_t alignment)
414 : d_allocator(allocator)
415 , d_bytes_p(p)
416 , d_nbytes(nbytes)
417 , d_alignment(alignment)
418{
419}
420
421template <class ALLOCATOR>
422inline
425 : d_allocator(MoveUtil::access(original).d_allocator)
426 , d_bytes_p(MoveUtil::access(original).d_bytes_p)
427 , d_nbytes(MoveUtil::access(original).d_nbytes)
428 , d_alignment(MoveUtil::access(original).d_alignment)
429{
430 MoveUtil::access(original).release();
431}
432
433template <class ALLOCATOR>
434inline
436{
437 if (d_bytes_p) {
438 doDeallocate(bsl::is_pointer<ALLOCATOR>());
439 }
440}
441
442// MANIPULATORS
443template <class ALLOCATOR>
444inline
445typename DeallocateBytesProctor<ALLOCATOR>::PtrType
447{
448 PtrType ret = d_bytes_p;
449 d_bytes_p = PtrType();
450 return ret;
451}
452
453template <class ALLOCATOR>
454inline
456 std::size_t nbytes,
457 std::size_t alignment)
458{
459 d_bytes_p = p;
460 d_nbytes = nbytes;
461 d_alignment = alignment;
462}
463
464// ACCESSORS
465template <class ALLOCATOR>
466inline
467typename DeallocateBytesProctor<ALLOCATOR>::PtrType
469{
470 return d_bytes_p;
471}
472
473} // close package namespace
474
475
476
477#endif // ! defined(INCLUDED_BSLMA_DEALLOCATEBYTESPROCTOR)
478
479// ----------------------------------------------------------------------------
480// Copyright 2023 Bloomberg Finance L.P.
481//
482// Licensed under the Apache License, Version 2.0 (the "License");
483// you may not use this file except in compliance with the License.
484// You may obtain a copy of the License at
485//
486// http://www.apache.org/licenses/LICENSE-2.0
487//
488// Unless required by applicable law or agreed to in writing, software
489// distributed under the License is distributed on an "AS IS" BASIS,
490// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
491// See the License for the specific language governing permissions and
492// limitations under the License.
493// ----------------------------- END-OF-FILE ----------------------------------
494
495/** @} */
496/** @} */
497/** @} */
Definition bslma_deallocatebytesproctor.h:272
~DeallocateBytesProctor()
Definition bslma_deallocatebytesproctor.h:435
PtrType release()
Definition bslma_deallocatebytesproctor.h:446
DeallocateBytesProctor(bslmf::MovableRef< DeallocateBytesProctor > original)
Definition bslma_deallocatebytesproctor.h:423
void reset(PtrType p, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_deallocatebytesproctor.h:455
DeallocateBytesProctor(const ALLOCATOR &allocator, PtrType p, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_deallocatebytesproctor.h:409
PtrType ptr() const
Definition bslma_deallocatebytesproctor.h:468
Definition bslmf_movableref.h:752
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:651
Definition baljsn_encoder_testtypes.h:76
BloombergLP::bslma::AllocatorTraits_VoidPointerType< ALLOCATOR_TYPE >::type void_pointer
Definition bslma_allocatortraits.h:1186
Definition bslmf_integralconstant.h:261
Definition bslmf_ispointer.h:138
static void deallocateBytes(const t_ALLOCATOR &allocator, typename AllocatorUtil_Traits< t_ALLOCATOR >::void_pointer p, std::size_t nbytes, std::size_t alignment=0)
Definition bslma_allocatorutil.h:930
void * type
Definition bslma_deallocatebytesproctor.h:383
Definition bslma_deallocatebytesproctor.h:371
bsl::allocator_traits< ALLOCATOR >::void_pointer type
Definition bslma_deallocatebytesproctor.h:373
Definition bslmf_movableref.h:795
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1039
@ BSLS_MAX_ALIGNMENT
Definition bsls_alignmentutil.h:300