BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslma_autodestructor.h
Go to the documentation of this file.
1/// @file bslma_autodestructor.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslma_autodestructor.h -*-C++-*-
8#ifndef INCLUDED_BSLMA_AUTODESTRUCTOR
9#define INCLUDED_BSLMA_AUTODESTRUCTOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslma_autodestructor bslma_autodestructor
15/// @brief Provide a range proctor to manage an array of objects.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslma
19/// @{
20/// @addtogroup bslma_autodestructor
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslma_autodestructor-purpose"> Purpose</a>
25/// * <a href="#bslma_autodestructor-classes"> Classes </a>
26/// * <a href="#bslma_autodestructor-description"> Description </a>
27/// * <a href="#bslma_autodestructor-usage"> Usage </a>
28///
29/// # Purpose {#bslma_autodestructor-purpose}
30/// Provide a range proctor to manage an array of objects.
31///
32/// # Classes {#bslma_autodestructor-classes}
33///
34/// - bslma::AutoDestructor: range proctor to manage an array of objects
35///
36/// @see bslma_destructorguard, bslma_destructorproctor
37///
38/// # Description {#bslma_autodestructor-description}
39/// This component provides a range proctor class template,
40/// `bslma::AutoDestructor`, to manage an array of (otherwise-unmanaged) objects
41/// of parameterized `TYPE` supplied at construction. Unless explicitly
42/// released, the contiguous managed objects are destroyed automatically when
43/// the range proctor goes out of scope by calling each (managed) object's
44/// destructor. Note that after a proctor object releases its managed objects,
45/// the same proctor can be reused to conditionally manage another contiguous
46/// sequence of objects by invoking the `reset` method.
47///
48/// ## Usage {#bslma_autodestructor-usage}
49///
50///
51/// `bslma::AutoDestructor` is normally used to achieve *exception* *safety* in
52/// an *exception* *neutral* way by automatically destroying
53/// (otherwise-unmanaged) orphaned objects for an "in-place" array should an
54/// exception occur. The following example illustrates the insertion operation
55/// for a generic array. Assume that the array initially contains the following
56/// five elements:
57/// @code
58/// 0 1 2 3 4
59/// _____ _____ _____ _____ _____ __
60/// | "A" | "B" | "C" | "D" | "E" |
61/// `=====^=====^=====^=====^=====^==
62/// @endcode
63/// To insert an element "F" at index position 2, the existing elements at index
64/// positions 2, 3, and 4 (i.e., "C", "D", and "E") are first shifted right to
65/// create an empty spot at the specified insert destination (we assume here and
66/// below that the array has sufficient capacity). The elements have to be
67/// shifted one by one by invoking the copy constructor (immediately followed by
68/// destroying the original elements). However, should any of the copy
69/// construction operations throw, all allocated resources from every previous
70/// copy construction would be leaked. Using the `bslma::AutoDestructor`
71/// prevents the leak by invoking the destructor of each of the previously
72/// copied elements should the proctor go out of scope before the `release`
73/// method of the proctor is called (such as when the function exits prematurely
74/// due to an exception):
75/// @code
76/// 0 1 2 3 4 5 6
77/// _____ _____ _____ _____ _____ _____ _____
78/// | "A" | "B" | "C" | "D" | "E" |xxxxx|xxxxx|
79/// `=====^=====^=====^=====^=====^=====^====='
80/// my_Array ^----- bslma::AutoDestructor
81/// (length = 5) (origin = 6, length = 0)
82///
83/// Note: "xxxxx" denotes uninitialized memory.
84/// @endcode
85/// As each of the elements at index positions beyond the insertion position is
86/// shifted up by one index position, the proctor (i.e., the proctor's length)
87/// is *decremented*, thereby *extending* by one the sequence of elements it
88/// manages *below* its origin (note that when the proctor's length is non-
89/// positive, the element at the origin is *not* managed). At the same time,
90/// the array's length is *decremented* to ensure that each array element is
91/// always being managed (during an allocation attempt) either by the proctor or
92/// the array itself, but not both:
93/// @code
94/// 0 1 2 3 4 5 6
95/// _____ _____ _____ _____ _____ _____ _____
96/// | "A" | "B" | "C" | "D" |xxxxx| "E" |xxxxx|
97/// `=====^=====^=====^=====^=====^=====^====='
98/// my_Array ^----------- bslma::AutoDestructor
99/// (length = 4) (origin = 6, length = -1)
100///
101/// Note: Configuration after shifting up one element.
102/// @endcode
103/// When all elements are shifted, the `bslma::AutoDestructor` will protect the
104/// entire range of shifted objects:
105/// @code
106/// 0 1 2 3 4 5 6
107/// _____ _____ _____ _____ _____ _____ _____
108/// | "A" | "B" |xxxxx| "C" | "D" | "E" |xxxxx|
109/// `=====^=====^=====^=====^=====^=====^====='
110/// my_Array ^----------------------- bslma::AutoDestructor
111/// (length = 2) (origin = 6, length = -3)
112///
113/// Note: Configuration after shifting up three elements.
114/// @endcode
115/// Next, a new copy of element "F" must be created. If, during creation, an
116/// allocation fails and an exception is thrown, the array (now of length 2) is
117/// in a valid state, while the proctor is responsible for destroying the
118/// orphaned elements at index positions 3, 4, and 5. If no exception is
119/// thrown, the proctor's `release` method is called, releasing its control over
120/// the temporarily-managed contents:
121/// @code
122/// // my_array.h
123/// // ...
124///
125/// /// This class implements an "in-place" array of objects of
126/// /// parameterized `TYPE` stored contiguously in memory.
127/// template <class TYPE>
128/// class my_Array {
129///
130/// // DATA
131/// TYPE *d_array_p; // dynamically allocated array
132/// int d_length; // logical length of this array
133/// int d_size; // physical capacity of this array
134/// bslma::Allocator *d_allocator_p; // allocator (held, not owned)
135///
136/// public:
137/// // CREATORS
138///
139/// /// Create a `my_Array` object having an initial length and capacity
140/// /// of 0. Optionally specify a `basicAllocator` used to supply
141/// /// memory. If `basicAllocator` is 0, the currently installed
142/// /// default allocator is used.
143/// my_Array(bslma::Allocator *basicAllocator = 0);
144///
145/// /// Create a `my_Array` object having an initial length of 0 and
146/// /// the specified `initialCapacity`. Optionally specify a
147/// /// `basicAllocator` used to supply memory. If `basicAllocator` is
148/// /// 0, the currently installed default allocator is used.
149/// my_Array(int initialCapacity, bslma::Allocator *basicAllocator = 0);
150///
151/// // ...
152///
153/// /// Destroy this `my_Array` object and all elements currently
154/// /// stored.
155/// ~my_Array();
156///
157/// // MANIPULATORS
158/// // ...
159///
160/// /// Insert (a copy of) the specified `object` of parameterized
161/// /// `TYPE` at the specified `dstIndex` position of this array. All
162/// /// values with initial indices at or above `dstIndex` are shifted
163/// /// up by one index position. The behavior is undefined unless
164/// /// `0 <= dstIndex` and `dstIndex` is less than the number of items
165/// /// in this array.
166/// void insert(int dstIndex, const TYPE& object);
167///
168/// // ...
169/// };
170/// @endcode
171/// Note that the rest of the `my_Array` interface (above) and implementation
172/// (below) is omitted as the portion shown is sufficient to demonstrate the use
173/// of `bslma::AutoDestructor`.
174/// @code
175/// // CREATORS
176/// template <class TYPE>
177/// inline
178/// my_Array<TYPE>::my_Array(bslma::Allocator *basicAllocator)
179/// : d_array_p(0)
180/// , d_length(0)
181/// , d_size(0)
182/// , d_allocator_p(bslma::Default::allocator(basicAllocator))
183/// {
184/// }
185///
186/// template <class TYPE>
187/// my_Array<TYPE>::~my_Array()
188/// {
189/// for (int i = 0; i < d_length; ++i) {
190/// d_array_p[i].~TYPE();
191/// }
192/// d_allocator_p->deallocate(d_array_p);
193/// }
194/// @endcode
195/// The elided implementation of the following `insert` function (which shows
196/// code for the case above, i.e., there is sufficient capacity) is sufficient
197/// to illustrate the use of `bslma::AutoDestructor`:
198/// @code
199/// // MANIPULATORS
200/// template <class TYPE>
201/// void my_Array<TYPE>::insert(int dstIndex, const TYPE& object)
202/// {
203/// BSLS_ASSERT(0 <= dstIndex);
204/// BSLS_ASSERT(dstIndex <= d_length);
205///
206/// if (d_size == d_length) { // resize needed
207/// // ...
208/// }
209///
210/// const TYPE *tmp = &object;
211///
212/// if ((d_array_p + dstIndex <= &object)
213/// && (&object < d_array_p + d_length)) { // self-aliasing
214/// tmp = &object + 1;
215/// }
216///
217/// //**************************************************************
218/// // Note the use of the auto destructor on 'd_array_p' (below). *
219/// //**************************************************************
220///
221/// bslma::AutoDestructor<TYPE> autoDtor(&d_array_p[d_length + 1], 0);
222/// int origLen = d_length;
223/// for (int i = d_length - 1; i >= dstIndex; --i, --autoDtor,
224/// --d_length) {
225/// new(&d_array_p[i + 1]) TYPE(d_array_p[i], d_allocator_p);
226/// // copy to new index
227/// d_array_p[i].~TYPE(); // destroy original
228/// }
229///
230/// new(&d_array_p[dstIndex]) TYPE(*tmp, d_allocator_p);
231///
232/// //*****************************************************
233/// // Note that the auto destructor is released (below). *
234/// //*****************************************************
235///
236/// autoDtor.release();
237///
238/// d_length = origLen + 1;
239/// }
240/// @endcode
241/// Note that the `insert` method assumes the copy constructor of `TYPE` takes
242/// an allocator as a second argument. In production code, a constructor proxy
243/// that checks the traits of `TYPE` (to determine whether `TYPE` indeed uses
244/// `bslma::Allocator`) should be used (see @ref bslalg_constructorproxy ).
245/// @}
246/** @} */
247/** @} */
248
249/** @addtogroup bsl
250 * @{
251 */
252/** @addtogroup bslma
253 * @{
254 */
255/** @addtogroup bslma_autodestructor
256 * @{
257 */
258
259#include <bslscm_version.h>
260
261#include <bsls_assert.h>
262#include <bsls_performancehint.h>
263
264
265
266namespace bslma {
267
268 // ====================
269 // class AutoDestructor
270 // ====================
271
272/// This class implements a range proctor that, unless its `release` method
273/// has previously been invoked, automatically destroys the contiguous
274/// sequence of managed objects upon its own destruction by invoking each
275/// object's destructor. If `release` is invoked (see `release`), the
276/// proctor will not destroy any objects upon its own destruction (unless
277/// `reset` is invoked to assign the proctor another contiguous sequence of objects for management).
278///
279/// \note Note that when the length of this object is
280/// non-zero, it must refer to a non-null array of objects.
281///
282/// See @ref bslma_autodestructor
283template <class TYPE>
285
286 // DATA
287 TYPE *d_origin_p; // reference location for the array of managed objects
288 int d_length; // number of objects to manage (sign encodes direction)
289
290 private:
291 // NOT IMPLEMENTED
293 AutoDestructor& operator=(const AutoDestructor&);
294
295 private:
296 // PRIVATE MANIPULATORS
297
298 /// Destroy the contiguous sequence of objects managed by this range
299 /// proctor (if any) by invoking the destructor of each (managed) object.
300 ///
301 /// \note Note that the order in which the managed objects are
302 /// destroyed is undefined. Also note that this method factors out the
303 /// destruction logic, which allows the destructor to be declared
304 /// `inline` for the common case (the range proctor is released before
305 /// being destroyed).
306 void destroy();
307
308 public:
309 // CREATORS
310
311 /// Create a range proctor to manage an array of objects at the
312 /// specified `origin`. Optionally specify `length` to define its
313 /// range, which by default is empty (i.e., `length = 0`). The sequence
314 /// of objects may extend in either direction from `origin`. A positive
315 /// `length` represents the sequence of objects starting at `origin` and
316 /// extending "up" to `length` (*not* including the object at the index
317 /// position `origin + length`). A negative `length` represents the
318 /// sequence of objects starting at one position below `origin` and
319 /// extending "down" to the absolute value of `length` (including the
320 /// object at index position `origin + length`). If `length` is 0, then
321 /// this range proctor manages no objects.
322 ///
323 /// \pre The behavior is undefined unless both `origin` and `length` are zero, or `origin` is non-zero
324 /// and all objects (if any) within the managed range (as defined by `length`) are valid.
325 ///
326 /// \note Note that when `length` is non-positive, the
327 /// object at the origin is *not* managed by this range proctor. For
328 /// example, if `origin` is at the index position 2, a `length` of 2
329 /// signifies that the objects at positions 2 and 3 are managed, whereas
330 /// a `length` of -2 signifies that the objects at positions 0 and 1 are
331 /// managed:
332 /// @code
333 /// length = -2 length = 2
334 /// |<----->| |<----->|
335 /// ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
336 /// | 0 | 1 | 2 | 3 | 4 | | 0 | 1 | 2 | 3 | 4 |
337 /// `===^===^===^===^===' `===^===^===^===^==='
338 /// ^------------ origin ^------------ origin
339 /// @endcode
340 explicit AutoDestructor(TYPE *origin, int length = 0);
341
342 /// Destroy this range proctor along with the contiguous sequence of
343 /// objects it manages (if any) by invoking the destructor of each (managed) object.
344 ///
345 /// \note Note that the order in which the managed objects
346 /// are destroyed is undefined.
348
349 // MANIPULATORS
350
351 /// Increase by one the (signed) length of the sequence of objects managed by this range proctor.
352 ///
353 /// \pre The behavior is undefined unless the
354 /// origin of the sequence of objects managed by this proctor is non-zero.
355 ///
356 /// \pre The behavior is undefined unless the origin of this range proctor is non-zero.
357 ///
358 /// \note Note that if the length of this proctor is
359 /// currently negative, the number of managed objects will decrease by
360 /// one, whereas if the length is non-negative, the number of managed
361 /// objects will increase by one.
362 void operator++();
363
364 /// Decrease by one the (signed) length of the sequence of objects managed by this range proctor.
365 ///
366 /// \pre The behavior is undefined unless the
367 /// origin of the sequence of objects managed by this proctor is non-zero.
368 ///
369 /// \pre The behavior is undefined unless the origin of this range proctor is non-zero.
370 ///
371 /// \note Note that if the length of this proctor is
372 /// currently positive, the number of managed objects will decrease by
373 /// one, whereas if the length is non-positive, the number of managed
374 /// objects will increase by one.
375 void operator--();
376
377 /// Release from management the sequence of objects currently managed by
378 /// this range proctor by setting the length of the managed sequence to
379 /// 0. All objects currently under management will become unmanaged
380 /// (i.e., when the proctor goes out of scope and it was not assigned
381 /// another sequence of objects to manage by invoking `reset`, no
382 /// objects will be destroyed). If no objects are currently being managed, this method has no effect.
383 ///
384 /// \note Note that the origin is not
385 /// affected.
386 void release();
387
388 /// Set the specified `origin` of the sequence of objects managed by
389 /// this range proctor. This method does not destroy the
390 /// previously-managed objects or affect the length of the sequence managed.
391 ///
392 /// \pre The behavior is undefined unless `origin` is non-zero.
393 ///
394 /// \note Note that `reset` can be called without having previously called
395 /// `release` provided that `length` is set appropriately before this
396 /// proctor could be destroyed (e.g., via a thrown exception).
397 void reset(TYPE *origin);
398
399 /// Set the (signed) length of the sequence of objects managed by this
400 /// range proctor to the specified `length`.
401 ///
402 /// \pre The behavior is undefined unless the origin of this range proctor is non-zero.
403 void setLength(int length);
404
405 // ACCESSORS
406
407 /// Return the (signed) length of the sequence of objects managed by
408 /// this range proctor.
409 int length() const;
410};
411
412// ============================================================================
413// INLINE DEFINITIONS
414// ============================================================================
415
416 // --------------------
417 // class AutoDestructor
418 // --------------------
419
420// PRIVATE MANIPULATORS
421template <class TYPE>
423{
424 if (0 < d_length) {
425 for (TYPE *next_p = d_origin_p; d_length > 0; --d_length) {
426 (next_p++)->~TYPE();
427 }
428 }
429 else {
430 for (TYPE *next_p = d_origin_p; d_length < 0; ++d_length) {
431 (--next_p)->~TYPE();
432 }
433 }
434
435 BSLS_ASSERT_SAFE(0 == d_length);
436}
437
438// CREATORS
439template <class TYPE>
440inline
442: d_origin_p(origin)
443, d_length(length)
444{
445 BSLS_ASSERT_SAFE(origin || !length);
446}
447
448template <class TYPE>
449inline
451{
452 BSLS_ASSERT_SAFE(d_origin_p || !d_length);
453
455 destroy();
456 }
457}
458
459// MANIPULATORS
460template <class TYPE>
461inline
463{
464 BSLS_ASSERT_SAFE(d_origin_p);
465
466 ++d_length;
467}
468
469template <class TYPE>
470inline
472{
473 BSLS_ASSERT_SAFE(d_origin_p);
474
475 --d_length;
476}
477
478template <class TYPE>
479inline
481{
482 d_length = 0;
483}
484
485template <class TYPE>
486inline
488{
489 BSLS_ASSERT_SAFE(origin);
490
491 d_origin_p = origin;
492}
493
494template <class TYPE>
495inline
497{
498 BSLS_ASSERT_SAFE(d_origin_p);
499
500 d_length = length;
501}
502
503// ACCESSORS
504template <class TYPE>
505inline
507{
508 return d_length;
509}
510
511} // close package namespace
512
513#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
514// ============================================================================
515// BACKWARD COMPATIBILITY
516// ============================================================================
517
518#ifdef bslma_AutoDestructor
519#undef bslma_AutoDestructor
520#endif
521/// This alias is defined for backward compatibility.
522#define bslma_AutoDestructor bslma::AutoDestructor
523#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
524
525
526
527#endif
528
529// ----------------------------------------------------------------------------
530// Copyright 2013 Bloomberg Finance L.P.
531//
532// Licensed under the Apache License, Version 2.0 (the "License");
533// you may not use this file except in compliance with the License.
534// You may obtain a copy of the License at
535//
536// http://www.apache.org/licenses/LICENSE-2.0
537//
538// Unless required by applicable law or agreed to in writing, software
539// distributed under the License is distributed on an "AS IS" BASIS,
540// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
541// See the License for the specific language governing permissions and
542// limitations under the License.
543// ----------------------------- END-OF-FILE ----------------------------------
544
545/** @} */
546/** @} */
547/** @} */
Definition bslma_autodestructor.h:284
void reset(TYPE *origin)
Definition bslma_autodestructor.h:487
void operator++()
Definition bslma_autodestructor.h:462
void release()
Definition bslma_autodestructor.h:480
int length() const
Definition bslma_autodestructor.h:506
void setLength(int length)
Definition bslma_autodestructor.h:496
~AutoDestructor()
Definition bslma_autodestructor.h:450
void operator--()
Definition bslma_autodestructor.h:471
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition baljsn_encoder_testtypes.h:76