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

Macros

#define bslalg_AutoArrayDestructor   bslalg::AutoArrayDestructor
 This alias is defined for backward compatibility.
 

Detailed Description

Outline

Purpose

Provide a proctor for destroying arrays.

Classes

See also
bslma_autodestructor

Description

This component provides a proctor object to manage a contiguous (in-place) sequence of otherwise-unmanaged instances of a user-defined type. If not explicitly released, all objects managed by the proctor object are automatically destroyed by the proctor's destructor, using the bslalg_arraydestructionprimitives .

In most instances, bslma::AutoDestructor can also be used, but this component is more useful in cases where it is simpler to think in terms of two pointers at the ends of the array being managed, rather than an origin and offset.

Usage

In this section we show intended use of this component.

Example 1: Managing an Array Under Construction

In most instances, the use of a bslalg::AutoArrayDestructor could be handled by a bslma::AutoDeallocator, but sometimes it is conceptually clearer to frame the problem in terms of a pair of pointers rather than a pointer and an offset.

Suppose we have a class, UsageType that allocates a block of memory upon construction, and whose constructor takes a char. Suppose we want to create an array of elements of such objects in an exception-safe manner.

First, we create the type UsageType:

// ===============
// class UsageType
// ===============
/// This test type contains a 'char' in some allocated storage. It has
/// no traits other than using a 'bslma' allocator.
class UsageType {
char *d_data_p; // managed single char
bslma::Allocator *d_allocator_p; // allocator (held, not owned)
public:
// CREATORS
explicit UsageType(char c, bslma::Allocator *basicAllocator = 0)
: d_data_p(0)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
d_data_p = (char *)d_allocator_p->allocate(sizeof(char));
*d_data_p = c;
}
~UsageType()
{
*d_data_p = '_';
d_allocator_p->deallocate(d_data_p);
d_data_p = 0;
}
// ACCESSORS
char datum() const
{
return *d_data_p;
}
};
namespace BloombergLP {
namespace bslma {
template <>
struct UsesBslmaAllocator<UsageType> : bsl::true_type {};
} // close package namespace
} // close enterprise namespace
Definition bslma_allocator.h:457
virtual void deallocate(void *address)=0
virtual void * allocate(size_type size)=0
Definition balxml_encoderoptions.h:68

Then, in main, we create a TestAllocator to supply memory (and to verify that no memory is leaked):

Definition bslma_testallocator.h:384

Next, we create the pointer for our array:

UsageType *array;

Then, we declare a string of characters we will use to initialize the UsageType objects in our array.

const char *DATA = "Hello";
const size_t DATA_LEN = std::strlen(DATA);

Next, we verify that even right after exceptions have been thrown and caught, no memory is outstanding:

assert(0 == ta.numBlocksInUse());
bsls::Types::Int64 numBlocksInUse() const
Definition bslma_testallocator.h:1087

Then, we allocate our array and create a guard to free it if a subsequent allocation throws an exception:

array = (UsageType *) ta.allocate(DATA_LEN * sizeof(UsageType));
Definition bslma_deallocatorproctor.h:312
void * allocate(size_type size) BSLS_KEYWORD_OVERRIDE

Next, we establish an AutoArrayDestructor on array to destroy any valid elements in array if an exception is thrown:

bslalg::AutoArrayDestructor<UsageType,> arrayElementProctor(array, array);
Definition bslalg_autoarraydestructor.h:232

Notice that we pass arrayElementProctor pointers to the beginning and end of the range to be guarded (we start with an empty range since no elements have been constructed yet).

Then, we iterate through the valid chars in DATA and use them to construct the elements of the array:

UsageType *resultElement = array;
for (const char *nextChar = DATA; *nextChar; ++nextChar) {

Next, construct the next element of array:

new (resultElement++) UsageType(*nextChar, &ta);

Now, move the end of arrayElementProctor to cover the most recently constructed element:

arrayElementProctor.moveEnd(1);
}

At this point, we have successfully created our array.

Then, release the guards so they won't destroy our work when they go out of scope:

arrayProctor.release();
arrayElementProctor.release();

Next, exit the exception testing block:

Then, verify that the array we have created is as expected:

assert('H' == array[0].datum());
assert('e' == array[1].datum());
assert('l' == array[2].datum());
assert('l' == array[3].datum());
assert('o' == array[4].datum());

Finally, destroy & free our work and verify that no memory is leaked:

for (size_t i = 0; i < DATA_LEN; ++i) {
array[i].~UsageType();
}
ta.deallocate(array);
assert(0 == ta.numBlocksInUse());
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE

Macro Definition Documentation

◆ bslalg_AutoArrayDestructor

#define bslalg_AutoArrayDestructor   bslalg::AutoArrayDestructor