BDE 4.14.0 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
278/// objects for management). Note that when the length of this object is
279/// non-zero, it must refer to a non-null array of objects.
280///
281/// See @ref bslma_autodestructor
282template <class TYPE>
284
285 // DATA
286 TYPE *d_origin_p; // reference location for the array of managed objects
287 int d_length; // number of objects to manage (sign encodes direction)
288
289 // NOT IMPLEMENTED
291 AutoDestructor& operator=(const AutoDestructor&);
292
293 private:
294 // PRIVATE MANIPULATORS
295
296 /// Destroy the contiguous sequence of objects managed by this range
297 /// proctor (if any) by invoking the destructor of each (managed)
298 /// object. Note that the order in which the managed objects are
299 /// destroyed is undefined. Also note that this method factors out the
300 /// destruction logic, which allows the destructor to be declared
301 /// `inline` for the common case (the range proctor is released before
302 /// being destroyed).
303 void destroy();
304
305 public:
306 // CREATORS
307
308 /// Create a range proctor to manage an array of objects at the
309 /// specified `origin`. Optionally specify `length` to define its
310 /// range, which by default is empty (i.e., `length = 0`). The sequence
311 /// of objects may extend in either direction from `origin`. A positive
312 /// `length` represents the sequence of objects starting at `origin` and
313 /// extending "up" to `length` (*not* including the object at the index
314 /// position `origin + length`). A negative `length` represents the
315 /// sequence of objects starting at one position below `origin` and
316 /// extending "down" to the absolute value of `length` (including the
317 /// object at index position `origin + length`). If `length` is 0, then
318 /// this range proctor manages no objects. The behavior is undefined
319 /// unless both `origin` and `length` are zero, or `origin` is non-zero
320 /// and all objects (if any) within the managed range (as defined by
321 /// `length`) are valid. Note that when `length` is non-positive, the
322 /// object at the origin is *not* managed by this range proctor. For
323 /// example, if `origin` is at the index position 2, a `length` of 2
324 /// signifies that the objects at positions 2 and 3 are managed, whereas
325 /// a `length` of -2 signifies that the objects at positions 0 and 1 are
326 /// managed:
327 /// @code
328 /// length = -2 length = 2
329 /// |<----->| |<----->|
330 /// ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
331 /// | 0 | 1 | 2 | 3 | 4 | | 0 | 1 | 2 | 3 | 4 |
332 /// `===^===^===^===^===' `===^===^===^===^==='
333 /// ^------------ origin ^------------ origin
334 /// @endcode
335 explicit AutoDestructor(TYPE *origin, int length = 0);
336
337 /// Destroy this range proctor along with the contiguous sequence of
338 /// objects it manages (if any) by invoking the destructor of each
339 /// (managed) object. Note that the order in which the managed objects
340 /// are destroyed is undefined.
342
343 // MANIPULATORS
344
345 /// Increase by one the (signed) length of the sequence of objects
346 /// managed by this range proctor. The behavior is undefined unless the
347 /// origin of the sequence of objects managed by this proctor is
348 /// non-zero. The behavior is undefined unless the origin of this range
349 /// proctor is non-zero. Note that if the length of this proctor is
350 /// currently negative, the number of managed objects will decrease by
351 /// one, whereas if the length is non-negative, the number of managed
352 /// objects will increase by one.
353 void operator++();
354
355 /// Decrease by one the (signed) length of the sequence of objects
356 /// managed by this range proctor. The behavior is undefined unless the
357 /// origin of the sequence of objects managed by this proctor is
358 /// non-zero. The behavior is undefined unless the origin of this range
359 /// proctor is non-zero. Note that if the length of this proctor is
360 /// currently positive, the number of managed objects will decrease by
361 /// one, whereas if the length is non-positive, the number of managed
362 /// objects will increase by one.
363 void operator--();
364
365 /// Release from management the sequence of objects currently managed by
366 /// this range proctor by setting the length of the managed sequence to
367 /// 0. All objects currently under management will become unmanaged
368 /// (i.e., when the proctor goes out of scope and it was not assigned
369 /// another sequence of objects to manage by invoking `reset`, no
370 /// objects will be destroyed). If no objects are currently being
371 /// managed, this method has no effect. Note that the origin is not
372 /// affected.
373 void release();
374
375 /// Set the specified `origin` of the sequence of objects managed by
376 /// this range proctor. This method does not destroy the
377 /// previously-managed objects or affect the length of the sequence
378 /// managed. The behavior is undefined unless `origin` is non-zero.
379 /// Note that `reset` can be called without having previously called
380 /// `release` provided that `length` is set appropriately before this
381 /// proctor could be destroyed (e.g., via a thrown exception).
382 void reset(TYPE *origin);
383
384 /// Set the (signed) length of the sequence of objects managed by this
385 /// range proctor to the specified `length`. The behavior is undefined
386 /// unless the origin of this range proctor is non-zero.
387 void setLength(int length);
388
389 // ACCESSORS
390
391 /// Return the (signed) length of the sequence of objects managed by
392 /// this range proctor.
393 int length() const;
394};
395
396// ============================================================================
397// INLINE DEFINITIONS
398// ============================================================================
399
400 // --------------------
401 // class AutoDestructor
402 // --------------------
403
404// PRIVATE MANIPULATORS
405template <class TYPE>
407{
408 if (0 < d_length) {
409 for (; d_length > 0; --d_length, ++d_origin_p) {
410 d_origin_p->~TYPE();
411 }
412 }
413 else {
414 --d_origin_p;
415 for (; d_length < 0; ++d_length, --d_origin_p) {
416 d_origin_p->~TYPE();
417 }
418 }
419}
420
421// CREATORS
422template <class TYPE>
423inline
425: d_origin_p(origin)
426, d_length(length)
427{
428 BSLS_ASSERT_SAFE(origin || !length);
429}
430
431template <class TYPE>
432inline
434{
435 BSLS_ASSERT_SAFE(d_origin_p || !d_length);
436
438 destroy();
439 }
440}
441
442// MANIPULATORS
443template <class TYPE>
444inline
446{
447 BSLS_ASSERT_SAFE(d_origin_p);
448
449 ++d_length;
450}
451
452template <class TYPE>
453inline
455{
456 BSLS_ASSERT_SAFE(d_origin_p);
457
458 --d_length;
459}
460
461template <class TYPE>
462inline
464{
465 d_length = 0;
466}
467
468template <class TYPE>
469inline
471{
472 BSLS_ASSERT_SAFE(origin);
473
474 d_origin_p = origin;
475}
476
477template <class TYPE>
478inline
480{
481 BSLS_ASSERT_SAFE(d_origin_p);
482
483 d_length = length;
484}
485
486// ACCESSORS
487template <class TYPE>
488inline
490{
491 return d_length;
492}
493
494} // close package namespace
495
496#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
497// ============================================================================
498// BACKWARD COMPATIBILITY
499// ============================================================================
500
501#ifdef bslma_AutoDestructor
502#undef bslma_AutoDestructor
503#endif
504/// This alias is defined for backward compatibility.
505#define bslma_AutoDestructor bslma::AutoDestructor
506#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
507
508
509
510#endif
511
512// ----------------------------------------------------------------------------
513// Copyright 2013 Bloomberg Finance L.P.
514//
515// Licensed under the Apache License, Version 2.0 (the "License");
516// you may not use this file except in compliance with the License.
517// You may obtain a copy of the License at
518//
519// http://www.apache.org/licenses/LICENSE-2.0
520//
521// Unless required by applicable law or agreed to in writing, software
522// distributed under the License is distributed on an "AS IS" BASIS,
523// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
524// See the License for the specific language governing permissions and
525// limitations under the License.
526// ----------------------------- END-OF-FILE ----------------------------------
527
528/** @} */
529/** @} */
530/** @} */
Definition bslma_autodestructor.h:283
void reset(TYPE *origin)
Definition bslma_autodestructor.h:470
void operator++()
Definition bslma_autodestructor.h:445
void release()
Definition bslma_autodestructor.h:463
int length() const
Definition bslma_autodestructor.h:489
void setLength(int length)
Definition bslma_autodestructor.h:479
~AutoDestructor()
Definition bslma_autodestructor.h:433
void operator--()
Definition bslma_autodestructor.h:454
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition balxml_encoderoptions.h:68