Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslma_bufferallocator
[Package bslma]

Support efficient memory allocations from a user-supplied buffer. More...

Namespaces

namespace  bslma

Detailed Description

Outline
Purpose:
Support efficient memory allocations from a user-supplied buffer.
Deprecated:
Use bdlma_bufferedsequentialallocator instead.
Classes:
bslma::BufferAllocator memory allocator from user-supplied buffer
See also:
Component bdlma_bufferedsequentialallocator
Description:
This component provides an allocator, bslma::BufferAllocator, that implements the bslma::Allocator protocol and sequentially allocates memory blocks from a fixed-size buffer that is supplied by the user at construction. If an allocation request exceeds the remaining space in the buffer, the return value is the result of invoking an optional callback function that was supplied at construction, or zero if no callback was specified. This component also provides static utility functions for allocating memory directly from a user-specified buffer:
   ,----------------------.
  ( bslma::BufferAllocator )
   `----------------------'
              |         ctor
              V
      ,----------------.
     ( bslma::Allocator )
      `----------------'
                      allocate
                      deallocate
                      dtor
Alignment Strategy:
The bslma::BufferAllocator allocates memory using one of the two alignment strategies: 1) MAXIMUM ALIGNMENT or 2) NATURAL ALIGNMENT.
  1. MAXIMUM ALIGNMENT: This strategy always allocates memory aligned with the most restrictive alignment on the host platform. The value is defined in bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT.
  2. NATURAL ALIGNMENT: This strategy allocates memory whose alignment depends on the requested number of bytes. An object of a fundamental type (int, etc.) is naturally aligned when it's size evenly divides its address. An object of an aggregate type has natural alignment if the alignment of the most-restrictively aligned sub-object evenly divides the address of the aggregate. Natural alignment is always at least as restrictive as the compiler's required alignment. When only the size of an aggregate is known, and not its composition, we compute the alignment by finding the largest integral power of 2 (up to and including bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT) that divides the requested (non-zero) number of bytes. This computed alignment is guaranteed to be at least as restrictive as any sub-object within the aggregate.
Usage:
The bslma::BufferAllocator class defined in this component is commonly used to allocate memory from a static buffer that does not require "deletion". The following snippet of code creates an array that obtains its memory from a fixed-sized buffer, but through the bslma::Allocator protocol:
  // my_shortarray.h

  // ...

  namespace bslma { class Allocator; }

  class my_ShortArray {
      short            *d_array_p;      // dynamically-allocated array of
                                        // 'short' integers

      int               d_size;         // physical size of 'd_array_p'

      int               d_length;       // logical length of 'd_array_p'

      bslma::Allocator *d_allocator_p;  // memory allocator (held, not owned)

    private:
      // PRIVATE MANIPULATORS
      void increaseSize();  // Increase the capacity by at least one element.

    public:
      // CREATORS
      my_ShortArray(bslma::Allocator *basicAllocator);
          // Create an empty array using the specified 'basicAllocator' to
          // supply memory.
      // ...

      ~my_ShortArray();
      void append(short value);
      const short& operator[](int index) const { return d_array_p[index]; }
      int length() const { return d_length; }
  };
The implementation of my_ShortArray is as follows:
  // my_shortarray.cpp
  #include <my_shortarray.h>

  enum { INITIAL_SIZE = 1, GROW_FACTOR = 2 };
  // ...

  my_ShortArray::my_ShortArray(bslma::Allocator *basicAllocator)
  : d_size(INITIAL_SIZE)
  , d_length(0)
  , d_allocator_p(basicAllocator)
  {
      assert(d_allocator_p);
      d_array_p =
          (short *) d_allocator_p->allocate(d_size * sizeof *d_array_p);
  }

  my_ShortArray::~my_ShortArray()
  {
      // CLASS INVARIANTS
      assert(d_array_p);
      assert(0 <= d_size);
      assert(0 <= d_length); assert(d_length <= d_size);
      assert(d_allocator_p);

      d_allocator_p->deallocate(d_array_p);
  }

  inline
  void my_ShortArray::append(short value)
  {
      if (d_length >= d_size) {
          increaseSize();
      }
      d_array_p[d_length++] = value;
  }

  static
  void reallocate(short **array, int newSize, int length,
                  bslma::Allocator *basicAllocator)
      // Reallocate memory in the specified 'array' to the specified
      // 'newSize' using the specified 'basicAllocator' or global new
      // operator.  The specified 'length' number of leading elements are
      // preserved.  Since the class invariant requires that the physical
      // capacity of the container may grow but never shrink, the behavior
      // is undefined unless length <= newSize.
  {
      assert(array);
      assert(1 <= newSize);
      assert(0 <= length);
      assert(length <= newSize);        // enforce class invariant
      assert(basicAllocator);

      short *tmp = *array;              // support exception neutrality
      *array = (short *) basicAllocator->allocate(newSize * sizeof **array);

      // COMMIT POINT

      memcpy(*array, tmp, length * sizeof **array);
      basicAllocator->deallocate(tmp);
  }

  void my_ShortArray::increaseSize()
  {
       int proposedNewSize = d_size * GROW_FACTOR;    // reallocate can throw
       assert(proposedNewSize > d_length);
       reallocate(&d_array_p, proposedNewSize, d_length, d_allocator_p);
       d_size = proposedNewSize;                      // we're committed
  }
  // ...
Use buffer allocator to allocate memory for my_ShortArray as follows:
  void *callbackFunc(int /* size */)
  {
      std::cerr << "Buffer allocator out of memory." << std::endl;
      exit(-1);
      return (void *) 0;
  }
  // ...

  int main(int argc, char *argv[])
  {
  // ...
      static char memory[1024];  // No alignment issue; see below.
      bslma::BufferAllocator allocator(memory, sizeof memory, callbackFunc);

      my_ShortArray mA(allocator);
      const my_ShortArray& A = mA;
      mA.append(123);
      mA.append(456);
  // ...
  }
Note that in the main function above, memory does not need to be aligned because bslma::BufferAllocator::allocate internally performs alignment for each requested memory block based on the allocator's alignment strategy.