BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslma_autodestructor

Macros

#define bslma_AutoDestructor   bslma::AutoDestructor
 This alias is defined for backward compatibility.
 

Detailed Description

Outline

Purpose

Provide a range proctor to manage an array of objects.

Classes

See also
bslma_destructorguard, bslma_destructorproctor

Description

This component provides a range proctor class template, bslma::AutoDestructor, to manage an array of (otherwise-unmanaged) objects of parameterized TYPE supplied at construction. Unless explicitly released, the contiguous managed objects are destroyed automatically when the range proctor goes out of scope by calling each (managed) object's destructor. Note that after a proctor object releases its managed objects, the same proctor can be reused to conditionally manage another contiguous sequence of objects by invoking the reset method.

Usage

bslma::AutoDestructor is normally used to achieve exception safety in an exception neutral way by automatically destroying (otherwise-unmanaged) orphaned objects for an "in-place" array should an exception occur. The following example illustrates the insertion operation for a generic array. Assume that the array initially contains the following five elements:

0 1 2 3 4
_____ _____ _____ _____ _____ __
| "A" | "B" | "C" | "D" | "E" |
`=====^=====^=====^=====^=====^==

To insert an element "F" at index position 2, the existing elements at index positions 2, 3, and 4 (i.e., "C", "D", and "E") are first shifted right to create an empty spot at the specified insert destination (we assume here and below that the array has sufficient capacity). The elements have to be shifted one by one by invoking the copy constructor (immediately followed by destroying the original elements). However, should any of the copy construction operations throw, all allocated resources from every previous copy construction would be leaked. Using the bslma::AutoDestructor prevents the leak by invoking the destructor of each of the previously copied elements should the proctor go out of scope before the release method of the proctor is called (such as when the function exits prematurely due to an exception):

0 1 2 3 4 5 6
_____ _____ _____ _____ _____ _____ _____
| "A" | "B" | "C" | "D" | "E" |xxxxx|xxxxx|
`=====^=====^=====^=====^=====^=====^====='
my_Array ^----- bslma::AutoDestructor
(length = 5) (origin = 6, length = 0)
Note: "xxxxx" denotes uninitialized memory.

As each of the elements at index positions beyond the insertion position is shifted up by one index position, the proctor (i.e., the proctor's length) is decremented, thereby extending by one the sequence of elements it manages below its origin (note that when the proctor's length is non- positive, the element at the origin is not managed). At the same time, the array's length is decremented to ensure that each array element is always being managed (during an allocation attempt) either by the proctor or the array itself, but not both:

0 1 2 3 4 5 6
_____ _____ _____ _____ _____ _____ _____
| "A" | "B" | "C" | "D" |xxxxx| "E" |xxxxx|
`=====^=====^=====^=====^=====^=====^====='
my_Array ^----------- bslma::AutoDestructor
(length = 4) (origin = 6, length = -1)
Note: Configuration after shifting up one element.

When all elements are shifted, the bslma::AutoDestructor will protect the entire range of shifted objects:

0 1 2 3 4 5 6
_____ _____ _____ _____ _____ _____ _____
| "A" | "B" |xxxxx| "C" | "D" | "E" |xxxxx|
`=====^=====^=====^=====^=====^=====^====='
my_Array ^----------------------- bslma::AutoDestructor
(length = 2) (origin = 6, length = -3)
Note: Configuration after shifting up three elements.

Next, a new copy of element "F" must be created. If, during creation, an allocation fails and an exception is thrown, the array (now of length 2) is in a valid state, while the proctor is responsible for destroying the orphaned elements at index positions 3, 4, and 5. If no exception is thrown, the proctor's release method is called, releasing its control over the temporarily-managed contents:

// my_array.h
// ...
/// This class implements an "in-place" array of objects of
/// parameterized `TYPE` stored contiguously in memory.
template <class TYPE>
class my_Array {
// DATA
TYPE *d_array_p; // dynamically allocated array
int d_length; // logical length of this array
int d_size; // physical capacity of this array
bslma::Allocator *d_allocator_p; // allocator (held, not owned)
public:
// CREATORS
/// Create a `my_Array` object having an initial length and capacity
/// of 0. Optionally specify a `basicAllocator` used to supply
/// memory. If `basicAllocator` is 0, the currently installed
/// default allocator is used.
my_Array(bslma::Allocator *basicAllocator = 0);
/// Create a `my_Array` object having an initial length of 0 and
/// the specified `initialCapacity`. Optionally specify a
/// `basicAllocator` used to supply memory. If `basicAllocator` is
/// 0, the currently installed default allocator is used.
my_Array(int initialCapacity, bslma::Allocator *basicAllocator = 0);
// ...
/// Destroy this `my_Array` object and all elements currently
/// stored.
~my_Array();
// MANIPULATORS
// ...
/// Insert (a copy of) the specified `object` of parameterized
/// `TYPE` at the specified `dstIndex` position of this array. All
/// values with initial indices at or above `dstIndex` are shifted
/// up by one index position. The behavior is undefined unless
/// `0 <= dstIndex` and `dstIndex` is less than the number of items
/// in this array.
void insert(int dstIndex, const TYPE& object);
// ...
};
Definition bslma_allocator.h:457

Note that the rest of the my_Array interface (above) and implementation (below) is omitted as the portion shown is sufficient to demonstrate the use of bslma::AutoDestructor.

// CREATORS
template <class TYPE>
inline
my_Array<TYPE>::my_Array(bslma::Allocator *basicAllocator)
: d_array_p(0)
, d_length(0)
, d_size(0)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
}
template <class TYPE>
my_Array<TYPE>::~my_Array()
{
for (int i = 0; i < d_length; ++i) {
d_array_p[i].~TYPE();
}
d_allocator_p->deallocate(d_array_p);
}
Definition balxml_encoderoptions.h:68

The elided implementation of the following insert function (which shows code for the case above, i.e., there is sufficient capacity) is sufficient to illustrate the use of bslma::AutoDestructor:

// MANIPULATORS
template <class TYPE>
void my_Array<TYPE>::insert(int dstIndex, const TYPE& object)
{
BSLS_ASSERT(0 <= dstIndex);
BSLS_ASSERT(dstIndex <= d_length);
if (d_size == d_length) { // resize needed
// ...
}
const TYPE *tmp = &object;
if ((d_array_p + dstIndex <= &object)
&& (&object < d_array_p + d_length)) { // self-aliasing
tmp = &object + 1;
}
//**************************************************************
// Note the use of the auto destructor on 'd_array_p' (below). *
//**************************************************************
bslma::AutoDestructor<TYPE> autoDtor(&d_array_p[d_length + 1], 0);
int origLen = d_length;
for (int i = d_length - 1; i >= dstIndex; --i, --autoDtor,
--d_length) {
new(&d_array_p[i + 1]) TYPE(d_array_p[i], d_allocator_p);
// copy to new index
d_array_p[i].~TYPE(); // destroy original
}
new(&d_array_p[dstIndex]) TYPE(*tmp, d_allocator_p);
//*****************************************************
// Note that the auto destructor is released (below). *
//*****************************************************
autoDtor.release();
d_length = origLen + 1;
}
Definition bslma_autodestructor.h:283
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804

Note that the insert method assumes the copy constructor of TYPE takes an allocator as a second argument. In production code, a constructor proxy that checks the traits of TYPE (to determine whether TYPE indeed uses bslma::Allocator) should be used (see bslalg_constructorproxy ).

Macro Definition Documentation

◆ bslma_AutoDestructor

#define bslma_AutoDestructor   bslma::AutoDestructor