BDE 4.14.0 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 void doDeallocate(bsl::false_type);
291 /// Deallocate the block at `d_bytes_p`. The first overload is selected
292 /// for non-pointer-type `ALLOCATOR` and invokes
293 /// `bslma::AllocatorUtil::deallocateBytes(d_allocator, d_bytes,
294 /// d_nbytes, d_alignment)`. The second overload is selected for a
295 /// pointer-type `ALLOCATOR` and invokes
296 /// `d_allocator->deallocate(d_object_p)`.
297 void doDeallocate(bsl::true_type);
298
299 // NOT IMPLEMENTED
303
304 public:
305 // CREATORS
306
307 /// Create a proctor to manage the specified `nbytes` bytes at the
308 /// specified `p` address, which have been allocated from the specified
309 /// `allocator`. Optionally specify the `alignment` used to allocate
310 /// the bytes. If `p` is null, then the created proctor is disengaged
311 /// (manages no memory). The behavior is undefined unless `p` is null
312 /// or was allocated from `allocator` with a size of `nbytes` and
313 /// alignment of `alignment`.
314 DeallocateBytesProctor(const ALLOCATOR& allocator,
315 PtrType p,
316 std::size_t nbytes,
317 std::size_t alignment = k_MAX_ALIGNMENT);
318
319 /// This move constructor creates a proctor managing the same block as
320 /// `original`. After the move, `original` is disengaged.
322
323 /// Deallocate the managed memory, if any, without invoking any other
324 /// destructors.
326
327 // MANIPULATORS
328
329 /// Disengage this allocator and return a pointer to the formerly
330 /// managed memory block.
331 PtrType release();
332
333 /// Release the managed memory and reset this proctor to manage the
334 /// specified `nbytes` bytes at the specified `p` address. Optionally
335 /// specify the `alignment` used to allocate `p`. If `p` is null, then
336 /// the proctor is disengaged (manages no memory). The behavior is
337 /// undefined unless `p` is null or was allocated with a size of
338 /// `nbytes` and alignment of `alignment` from the same allocator used
339 /// to construct this proctor. Note that the previously managed block
340 /// is not deallocated.
341 void reset(PtrType p,
342 std::size_t nbytes,
343 std::size_t alignment = k_MAX_ALIGNMENT);
344
345 // ACCESSORS
346
347 /// Return the address of the currently managed memory block, if
348 /// engaged; otherwise return a null pointer.
349 PtrType ptr() const;
350};
351
352// ============================================================================
353// TEMPLATE AND INLINE FUNCTION IMPLEMENTATIONS
354// ============================================================================
355
356 // ----------------------------------------------
357 // struct template DeallocateBytesProctor_PtrType
358 // ----------------------------------------------
359
360/// This metafunction has a nested `type` that indicates the correct `void`
361/// pointer type to use to manage bytes allocated from an allocator having
362/// the specified `ALLOCATOR` template parameter type. This primary
363/// template yields the @ref void_pointer type specified by the
364/// `allocator_traits` for `ALLOCATOR`.
365template <class ALLOCATOR>
371
372/// This partial specialization is chosen when `ALLOCATOR` is a pointer type
373/// (i.e., `bslma::Allocator *` or a pointer to a pool class). It yields
374/// a `type` of `void *`.
375template <class ALLOCATOR>
377{
378
379 typedef void *type;
380};
381
382 // --------------------------------------
383 // class template DeallocateBytesProctor
384 // --------------------------------------
385
386// PRIVATE MANIPULATORS
387template <class ALLOCATOR>
388inline
390{
391 bslma::AllocatorUtil::deallocateBytes(d_allocator, d_bytes_p,
392 d_nbytes, d_alignment);
393}
394
395template <class ALLOCATOR>
396inline
397void DeallocateBytesProctor<ALLOCATOR>::doDeallocate(bsl::true_type)
398{
399 d_allocator->deallocate(d_bytes_p);
400}
401
402// CREATORS
403template <class ALLOCATOR>
404inline
406 const ALLOCATOR& allocator,
407 PtrType p,
408 std::size_t nbytes,
409 std::size_t alignment)
410 : d_allocator(allocator)
411 , d_bytes_p(p)
412 , d_nbytes(nbytes)
413 , d_alignment(alignment)
414{
415}
416
417template <class ALLOCATOR>
418inline
421 : d_allocator(MoveUtil::access(original).d_allocator)
422 , d_bytes_p(MoveUtil::access(original).d_bytes_p)
423 , d_nbytes(MoveUtil::access(original).d_nbytes)
424 , d_alignment(MoveUtil::access(original).d_alignment)
425{
426 MoveUtil::access(original).release();
427}
428
429template <class ALLOCATOR>
430inline
432{
433 if (d_bytes_p) {
434 doDeallocate(bsl::is_pointer<ALLOCATOR>());
435 }
436}
437
438// MANIPULATORS
439template <class ALLOCATOR>
440inline
441typename DeallocateBytesProctor<ALLOCATOR>::PtrType
443{
444 PtrType ret = d_bytes_p;
445 d_bytes_p = PtrType();
446 return ret;
447}
448
449template <class ALLOCATOR>
450inline
452 std::size_t nbytes,
453 std::size_t alignment)
454{
455 d_bytes_p = p;
456 d_nbytes = nbytes;
457 d_alignment = alignment;
458}
459
460// ACCESSORS
461template <class ALLOCATOR>
462inline
463typename DeallocateBytesProctor<ALLOCATOR>::PtrType
465{
466 return d_bytes_p;
467}
468
469} // close package namespace
470
471
472
473#endif // ! defined(INCLUDED_BSLMA_DEALLOCATEBYTESPROCTOR)
474
475// ----------------------------------------------------------------------------
476// Copyright 2023 Bloomberg Finance L.P.
477//
478// Licensed under the Apache License, Version 2.0 (the "License");
479// you may not use this file except in compliance with the License.
480// You may obtain a copy of the License at
481//
482// http://www.apache.org/licenses/LICENSE-2.0
483//
484// Unless required by applicable law or agreed to in writing, software
485// distributed under the License is distributed on an "AS IS" BASIS,
486// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
487// See the License for the specific language governing permissions and
488// limitations under the License.
489// ----------------------------- END-OF-FILE ----------------------------------
490
491/** @} */
492/** @} */
493/** @} */
Definition bslma_deallocatebytesproctor.h:272
~DeallocateBytesProctor()
Definition bslma_deallocatebytesproctor.h:431
PtrType release()
Definition bslma_deallocatebytesproctor.h:442
DeallocateBytesProctor(bslmf::MovableRef< DeallocateBytesProctor > original)
Definition bslma_deallocatebytesproctor.h:419
void reset(PtrType p, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_deallocatebytesproctor.h:451
DeallocateBytesProctor(const ALLOCATOR &allocator, PtrType p, std::size_t nbytes, std::size_t alignment=k_MAX_ALIGNMENT)
Definition bslma_deallocatebytesproctor.h:405
PtrType ptr() const
Definition bslma_deallocatebytesproctor.h:464
Definition bslmf_movableref.h:751
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:609
Definition balxml_encoderoptions.h:68
BloombergLP::bslma::AllocatorTraits_VoidPointerType< ALLOCATOR_TYPE >::type void_pointer
Definition bslma_allocatortraits.h:1155
Definition bslmf_integralconstant.h:244
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=k_MAX_ALIGNMENT)
Definition bslma_allocatorutil.h:911
void * type
Definition bslma_deallocatebytesproctor.h:379
Definition bslma_deallocatebytesproctor.h:367
bsl::allocator_traits< ALLOCATOR >::void_pointer type
Definition bslma_deallocatebytesproctor.h:369
Definition bslmf_movableref.h:791
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1032
@ BSLS_MAX_ALIGNMENT
Definition bsls_alignmentutil.h:275