BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslma_deallocateobjectproctor.h
Go to the documentation of this file.
1/// @file bslma_deallocateobjectproctor.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslma_deallocateobjectproctor.h -*-C++-*-
8#ifndef INCLUDED_BSLMA_DEALLOCATEOBJECTPROCTOR
9#define INCLUDED_BSLMA_DEALLOCATEOBJECTPROCTOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslma_deallocateobjectproctor bslma_deallocateobjectproctor
15/// @brief Provide a proctor to conditionally unwind object allocation.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslma
19/// @{
20/// @addtogroup bslma_deallocateobjectproctor
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslma_deallocateobjectproctor-purpose"> Purpose</a>
25/// * <a href="#bslma_deallocateobjectproctor-classes"> Classes </a>
26/// * <a href="#bslma_deallocateobjectproctor-description"> Description </a>
27/// * <a href="#bslma_deallocateobjectproctor-usage"> Usage </a>
28///
29/// # Purpose {#bslma_deallocateobjectproctor-purpose}
30/// Provide a proctor to conditionally unwind object allocation.
31///
32/// # Classes {#bslma_deallocateobjectproctor-classes}
33///
34/// - bslma::DeallocateObjectProctor: proctor to conditionally unwind allocation.
35///
36/// @see bslma_deallocatebytesproctor, bslma_deleteobjectproctor
37///
38/// # Description {#bslma_deallocateobjectproctor-description}
39/// This component provides a proctor class template,
40/// `bslma::DeallocateObjectProctor`, that conditionally reverses the effect of
41/// `bslma::AllocatorUtil::allocateObject<TYPE>` or '(TYPE *)
42/// bslmAllocator->allocate(n)'. Upon destruction, this proctor deallocates the
43/// object from the specified allocator or pool without calling the object's
44/// destructor. The proctor's constructor takes the same arguments as
45/// `bslma::AllocatorUtil::deallocateObject`, making it straightforward to
46/// allocate an object using `allocateObject` and protect it using
47/// `DeallocateObjectProctor`.
48///
49/// As with all proctors, this class is used to automatically reclaim a resource
50/// in the event that a function ends prematurely, e.g., via an exception.
51/// After allocating an object, an exception-safe function would create a
52/// `DeallocateObjectProctor` to manage the new object's memory. If the
53/// operation completes successfully, the code calls the proctor's `release`
54/// method, which disengages the proctor. If, however, the function exits while
55/// the proctor is still engaged, the proctor's destructor will deallocate the
56/// managed memory.
57///
58/// The `DeallocateObjectProctor` template has two template parameters: the
59/// `ALLOCATOR` type used to reclaim storage and the object `TYPE` managed by
60/// the proctor. If `ALLOCATOR` is a non-pointer type and `TYPE` is omitted, it
61/// is deduced as `ALLOCATOR::value_type`. However, if `TYPE` is supplied, it
62/// overrides `ALLOCATOR::value_type`.
63///
64/// If `ALLOCATOR` is a non-pointer type, the proctor uses
65/// `bslma::AllocatorUtil::deleteObject(a, ptr, n)` to reclaim storage, where
66/// `a` is the allocator, `ptr` is the address of the managed object, and `n` is
67/// the number of managed objects. Otherwise, if `ALLOCATOR` is a pointer type,
68/// the proctor reclaims memory by calling `a->deallocate(ptr)`. Instantiating
69/// `DeallocateObjectProctor` with a pointer-type `ALLOCATOR` is appropriate for
70/// classes derived from `bslma::Allocator` and for BDE-style pool types, i.e.,
71/// classes for which `a->deallocate(ptr)` is well formed.
72///
73/// ## Usage {#bslma_deallocateobjectproctor-usage}
74///
75///
76/// These examples illustrate the intended use of this component.
77///
78///Example 1: Class having an owning pointer
79///- - - - - - - - - - - - - - - - - - - - -
80/// In this example, we create a class, `my_Manager`, having an owning pointer
81/// to an object of another class, `my_Data`. Because it owns the `my_Data`
82/// object, `my_Manager` is responsible for allocating, constructing,
83/// deallocating, and destroying it.
84///
85/// First, we define the `my_Data` class, which holds an integer value and
86/// counts how many times its constructor and destructor have been called. Its
87/// constructor will throw an exception if its integer argument equals the
88/// number of constructor calls before construction:
89/// @code
90/// #include <bslma_allocatorutil.h>
91/// #include <bslma_bslallocator.h>
92/// #include <bslma_testallocator.h>
93///
94/// class my_Data {
95///
96/// // DATA
97/// int d_value;
98///
99/// // CLASS DATA
100/// static int s_numConstructed;
101/// static int s_numDestroyed;
102///
103/// public:
104/// // CLASS METHODS
105/// static int numConstructed() { return s_numConstructed; }
106/// static int numDestroyed() { return s_numDestroyed; }
107///
108/// // CREATORS
109/// explicit my_Data(int v) : d_value(v)
110/// {
111/// if (v == s_numConstructed) throw s_numConstructed;
112/// ++s_numConstructed;
113/// }
114/// my_Data(const my_Data& original);
115/// ~my_Data() { ++s_numDestroyed; }
116/// };
117///
118/// int my_Data::s_numConstructed = 0;
119/// int my_Data::s_numDestroyed = 0;
120/// @endcode
121/// Next, we define `my_Manager` as an allocator-aware class holding a pointer
122/// to `my_Data` and maintaining its own count of constructor invocations:
123/// @code
124/// class my_Manager {
125///
126/// // DATA
127/// bsl::allocator<my_Data> d_allocator;
128/// my_Data *d_data_p;
129///
130/// // CLASS DATA
131/// static int s_numConstructed;
132///
133/// public:
134/// // TYPES
135/// typedef bsl::allocator<> allocator_type;
136///
137/// // CLASS METHODS
138/// static int numConstructed() { return s_numConstructed; }
139///
140/// // CREATORS
141/// explicit my_Manager(int v,
142/// const allocator_type& allocator = allocator_type());
143/// my_Manager(const my_Manager& original);
144/// ~my_Manager();
145///
146/// // ...
147/// };
148///
149/// int my_Manager::s_numConstructed = 0;
150/// @endcode
151/// Next, we define the constructor for `my_Manager`, which begins by allocating
152/// a `my_Data` object:
153/// @code
154/// my_Manager::my_Manager(int v, const allocator_type& allocator)
155/// : d_allocator(allocator), d_data_p(0)
156/// {
157/// d_data_p = bslma::AllocatorUtil::allocateObject<my_Data>(allocator);
158/// @endcode
159/// Then, the `my_Manager` constructor constructs the `my_Data` object in the
160/// allocated memory. However, as the constructor might throw it first protects
161/// the data object with a `bslma::DeallocateObjectProctor`:
162/// @code
163/// bslma::DeallocateObjectProctor<allocator_type, my_Data>
164/// proctor(d_allocator, d_data_p);
165/// bslma::ConstructionUtil::construct(d_data_p, d_allocator, v);
166/// @endcode
167/// Then, once the `construct` operation completes successfully, we can release
168/// the data object from the proctor. Only then do we increment the
169/// construction count:
170/// @code
171/// proctor.release();
172/// ++s_numConstructed;
173/// }
174/// @endcode
175/// Next, we define the `my_Manager` destructor, which destroys and deallocates
176/// its data object:
177/// @code
178/// my_Manager::~my_Manager()
179/// {
180/// d_data_p->~my_Data();
181/// bslma::AllocatorUtil::deallocateObject(d_allocator, d_data_p);
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 was deallocated, resulting in no leaks:
206/// @code
207/// try {
208/// my_Manager obj2(1, &ta);
209/// assert(false && "Can't get here");
210/// }
211/// catch (int e) {
212/// assert(1 == e);
213/// assert(0 == ta.numBlocksInUse());
214/// assert(2 == ta.numBlocksTotal());
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_deallocateobjectproctor
231 * @{
232 */
233
234#include <bslscm_version.h>
235
237#include <bslma_allocatorutil.h>
238
240#include <bslmf_ispointer.h>
241#include <bslmf_issame.h>
242#include <bslmf_movableref.h>
243
244#include <bsls_keyword.h>
245
246#include <cstdlib> // std::size_t
247
248
249namespace bslma {
250
251// FORWARD DECLARATIONS
252template <class ALLOCATOR, class TYPE>
253struct DeallocateObjectProctor_PtrType;
254
255 // ======================================
256 // class template DeallocateObjectProctor
257 // ======================================
258
259/// This class implements a proctor that, unless its `release` method has
260/// previously been invoked, automatically deallocates a managed object upon
261/// destruction by invoking the `deallocate` method of an allocator (or
262/// pool) of parameterized `ALLOCATOR` type supplied to it at construction.
263/// The managed object of parameterized `TYPE` must be memory that was
264/// provided by this allocator (or pool); the allocator (or pool) must
265/// remain valid throughout the lifetime of the proctor object. If
266/// `ALLOCATOR` is a non-pointer type, it is assumed to be STL compatible;
267/// otherwise, it is assumed have a `deallocate` method with a single 'void
268/// *' parameter, i.e., the same deallocation interface as
269/// `bslma::Allocator`.
270///
271/// See @ref bslma_deallocateobjectproctor
272template <class ALLOCATOR, class TYPE = typename ALLOCATOR::value_type>
274
275 private:
276 // PRIVATE TYPES
278 typedef typename DeallocateObjectProctor_PtrType<ALLOCATOR,
279 TYPE>::type PtrType;
280
281 // DATA
282 ALLOCATOR d_allocator; // allocator object (might be a pointer)
283 PtrType d_object_p; // managed object (null if disengaged)
284 std::size_t d_numObjects; // number of managed objects
285
286 // PRIVATE MANIPULATORS
287
288 // Deallocate the object at `d_object_p`. The first overload is
289 // selected for non-pointer-type `ALLOCATOR` and invokes
290 // `AllocatorUtil::deallocateObject`. The second overload is selected
291 // for a pointer-type `ALLOCATOR` and invokes
292 // `d_allocator->deallocate(d_object_p)`.
293 void doDeallocate(bsl::false_type);
294 void doDeallocate(bsl::true_type);
295
296 // NOT IMPLEMENTED
301
302 public:
303 // CREATORS
304
305 /// Create a proctor to manage the optionally specified `n` objects at
306 /// the specified `p` address, which have been allocated from the
307 /// specified `allocator`. If `p` is null, then the created proctor is
308 /// disengaged (manages no objects). The behavior is undefined if `p`
309 /// is non-null but not allocated from `allocator` or if `p` does not
310 /// point to an array of `n` objects.
311 DeallocateObjectProctor(const ALLOCATOR& allocator,
312 PtrType p,
313 std::size_t n = 1);
314
315 /// This move constructor creates a proctor managing the same object as
316 /// `original`. After the move, `original` is disengaged.
319
320 /// Deallocate the managed objects, if any. Note that the managed
321 /// objects' destructors are not invoked.
323
324 // MANIPULATORS
325
326 /// Disengage this allocator and return a pointer to the formerly
327 /// managed object(s).
328 PtrType release();
329
330 /// Release the managed object and reset this proctor to manage the
331 /// specified `p` pointer to optionally specified `n` objects. If `p`
332 /// is null, then the proctor will be disenaged. Note that the
333 /// previously managed objects are not deallocated.
334 void reset(PtrType p, std::size_t n = 1);
335
336 // ACCESSORS
337
338 /// Return the address of the currently managed objects, if engaged;
339 /// otherwise return a null pointer.
340 PtrType ptr() const;
341};
342
343// ============================================================================
344// TEMPLATE AND INLINE FUNCTION IMPLEMENTATIONS
345// ============================================================================
346
347 // -----------------------------------------------
348 // struct template DeallocateObjectProctor_PtrType
349 // -----------------------------------------------
350
351/// This metafunction has a nested `type` that indicates the correct pointer
352/// type to use to manage an object of the specified `TYPE` template
353/// parameter allocated from an allocator having the specified `ALLOCATOR`
354/// template parameter type. This primary template yields the pointer type
355/// specified by `ALLOCATOR`, after rebinding to the specified `TYPE`.
356template <class ALLOCATOR, class TYPE>
358{
359
360 typedef typename bsl::allocator_traits<ALLOCATOR>::
361 template rebind_traits<TYPE>::pointer type;
362};
363
364/// This partial specialization is chosen when `ALLOCATOR` is a pointer type
365/// (i.e., `bslma::Allocator *` or a pointer to a pool class). It yields
366/// `TYPE *` for `type`.
367template <class ALLOCATOR, class TYPE>
368struct DeallocateObjectProctor_PtrType<ALLOCATOR *, TYPE>
369{
370
371 typedef TYPE *type;
372};
373
374 // --------------------------------------
375 // class template DeallocateObjectProctor
376 // --------------------------------------
377
378// PRIVATE MANIPULATORS
379template <class ALLOCATOR, class TYPE>
380inline
382{
383 AllocatorUtil::deallocateObject(d_allocator, d_object_p, d_numObjects);
384}
385
386template <class ALLOCATOR, class TYPE>
387inline
388void DeallocateObjectProctor<ALLOCATOR, TYPE>::doDeallocate(bsl::true_type)
389{
390 // When `ALLOCATOR` is a pointer type, assume that `deallocate` can be
391 // called with a single pointer argument. We cannot use
392 // `AllocatorUtil::deallocateObject` because `AllocatorUtil` does not work
393 // with pool types, which are neither STL allocators nor derived from
394 // `bslma::Allocator`.
395 d_allocator->deallocate(d_object_p);
396}
397
398// CREATORS
399template <class ALLOCATOR, class TYPE>
400inline
402 const ALLOCATOR& allocator,
403 PtrType p,
404 std::size_t n)
405 : d_allocator(allocator), d_object_p(p), d_numObjects(n)
406{
407}
408
409template <class ALLOCATOR, class TYPE>
410inline
413 : d_allocator(MoveUtil::access(original).d_allocator)
414 , d_object_p(MoveUtil::access(original).d_object_p)
415 , d_numObjects(MoveUtil::access(original).d_numObjects)
416{
417 MoveUtil::access(original).release();
418}
419
420template <class ALLOCATOR, class TYPE>
421inline
423{
424 if (d_object_p) {
425 // Dispatch to the appropriate version of `doDelete`, depending on
426 // whether or not `ALLOCATOR` is a pointer type. We cannot simply call
427 // `AllocatorUtil::dealocateObject` unconditionally because
428 // `AllocatorUtil` does not work with pool types, which are neither STL
429 // allocators nor derived from `bslma::Allocator`.
430 doDeallocate(bsl::is_pointer<ALLOCATOR>());
431 }
432}
433
434// MANIPULATORS
435template <class ALLOCATOR, class TYPE>
436inline
437typename DeallocateObjectProctor<ALLOCATOR, TYPE>::PtrType
439{
440 PtrType ret = d_object_p;
441 d_object_p = PtrType();
442 return ret;
443}
444
445template <class ALLOCATOR, class TYPE>
446inline
448{
449 d_object_p = p;
450 d_numObjects = n;
451}
452
453// ACCESSORS
454template <class ALLOCATOR, class TYPE>
455inline
456typename DeallocateObjectProctor<ALLOCATOR, TYPE>::PtrType
458{
459 return d_object_p;
460}
461
462} // close package namespace
463
464
465
466#endif // ! defined(INCLUDED_BSLMA_DEALLOCATEOBJECTPROCTOR)
467
468// ----------------------------------------------------------------------------
469// Copyright 2023 Bloomberg Finance L.P.
470//
471// Licensed under the Apache License, Version 2.0 (the "License");
472// you may not use this file except in compliance with the License.
473// You may obtain a copy of the License at
474//
475// http://www.apache.org/licenses/LICENSE-2.0
476//
477// Unless required by applicable law or agreed to in writing, software
478// distributed under the License is distributed on an "AS IS" BASIS,
479// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
480// See the License for the specific language governing permissions and
481// limitations under the License.
482// ----------------------------- END-OF-FILE ----------------------------------
483
484/** @} */
485/** @} */
486/** @} */
Definition bslma_deallocateobjectproctor.h:273
PtrType ptr() const
Definition bslma_deallocateobjectproctor.h:457
void reset(PtrType p, std::size_t n=1)
Definition bslma_deallocateobjectproctor.h:447
~DeallocateObjectProctor()
Definition bslma_deallocateobjectproctor.h:422
PtrType release()
Definition bslma_deallocateobjectproctor.h:438
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
Definition bslma_allocatortraits.h:1061
Definition bslmf_integralconstant.h:244
Definition bslmf_ispointer.h:138
static void deallocateObject(const t_ALLOCATOR &allocator, t_POINTER p, std::size_t n=1)
Definition bslma_allocatorutil.h:926
TYPE * type
Definition bslma_deallocateobjectproctor.h:371
Definition bslma_deallocateobjectproctor.h:358
bsl::allocator_traits< ALLOCATOR >::template rebind_traits< TYPE >::pointer type
Definition bslma_deallocateobjectproctor.h:361
Definition bslmf_movableref.h:791
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1032