Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslalg_autoarraydestructor
[Package bslalg]

Provide a proctor for destroying arrays. More...

Namespaces

namespace  bslalg

Detailed Description

Outline
Purpose:
Provide a proctor for destroying arrays.
Classes:
bslalg::AutoArrayDestructor exception-neutrality proctor for arrays
See also:
Component 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
                               // ===============

  class UsageType {
      // This test type contains a 'char' in some allocated storage.  It has
      // no traits other than using a 'bslma' allocator.

      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
Then, in main, we create a TestAllocator to supply memory (and to verify that no memory is leaked): 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());
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));
  bslma::DeallocatorProctor<bslma::Allocator> arrayProctor(array, &ta);
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);
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());