Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bsls_alignedbuffer
[Package bsls]

Provide raw buffers with user-specified size and alignment. More...

Namespaces

namespace  bsls

Detailed Description

Outline
Purpose:
Provide raw buffers with user-specified size and alignment.
Classes:
bsls::AlignedBuffer Uninitialized buffer of specified size and alignment
See also:
Component bsls_objectbuffer, Component bsls_alignmenttotype
Description:
This component provides a templated buffer type with a user-specified compile-time size and user-specified alignment. The user instantiates bsls::AlignedBuffer with specific size and alignment requirements, and then uses that memory as needed. If an alignment is not specified at template instantiation, then the buffer object is maximally aligned.
Typically, bsls::AlignedBuffer is used in situations where it is desirable to allocate a block of properly-aligned raw memory from somewhere other than the heap, e.g., on the stack or within an aggregate object, including within a union. It is a convenient way to create a small heap from which one or more objects are allocated at run-time.
Single-Object Buffers:
Although, for a given type T, bsls::AlignedBuffer<sizeof(T), bsls::AlignmentFromType<T>VALUE> will produce a buffer properly sized and aligned to hold a T object, it is simpler and clearer to use bsls::ObjectBuffer<T> for this purpose. See the bsls_objectbuffer component for more information.
Stack Alignment:
On platforms with 32-bit words, there is usually no efficiency gain by using more than 4-byte alignment. Yet some compilers use 8-byte alignment for long long or double, presumably so that the code will run faster on a future 64-bit CPU. The program loader, however, has no reason to presume more than 4-byte alignment when allocating the program stack. This can result in stack objects appearing to be misaligned relative to the alignments computed by this component. This is not a bug in either this component nor in the compiler, but it is somewhat surprising. We have seen this behavior on the MS VC++ 7 platform. See also the "Surprises and Anomalies" section in bsls_alignmentfromtype.h.
Known issues:
On all versions of the Microsoft compiler prior to MSVC 14.0 (2015), passing AlignedBuffer or an object containing AlignedBuffer as a by-value function argument would lead to C2719 error (see https://msdn.microsoft.com/en-us/library/373ak2y1.aspx). In versions 14.10 (2017) through 16.8 (2019) it can trigger a compiler bug leading to crashes due to the destructor being invoked with an incorrect this pointer. This bug has been observed only building for x86 (32-bit) platform in Debug mode (specifically with /Od /Ob0 flags), e.g.:
  struct X {
      bsls::AlignedBuffer<1, 8> d_buffer;
  };

  void func(X) {}

  int main()
  {
      func(X());  // The destructor of 'X' is called with broken 'this'.
  }
See DRQS 151904020 for more details.
This was fixed my Microsoft in MSVC 2019 version 16.9, for details see: https://developercommunity.visualstudio.com/t/incorrect-code-gen-missing-error/831543
Usage:
The allocateFromBuffer function below uses an aligned buffer as a small heap from which objects can be allocated. We choose int alignment (4-byte alignment) for our buffer because the objects we are allocating are composed of char, short, and int values only. If no alignment were specified, the buffer would be maximally aligned, which could be wasteful on some platforms.
  const int MY_ALIGNMENT = bsls::AlignmentFromType<int>::VALUE;
  bsls::AlignedBuffer<1000, MY_ALIGNMENT> my_AllocBuffer;
  const char* my_AllocEnd = my_AllocBuffer.buffer() + 1000;
  char *my_AllocPtr = my_AllocBuffer.buffer();
      // Invariant: my_AllocPtr is always aligned on a multiple of 4 bytes

  static void *allocateFromBuffer(int size)
  {
      if (size > my_AllocEnd - my_AllocPtr)
          return 0;       // Out of buffer space

      void *result = my_AllocPtr;
      my_AllocPtr += size;
      if (size % MY_ALIGNMENT) {
          // re-establish invariant by re-aligning my_AllocPtr
          my_AllocPtr += MY_ALIGNMENT - size % MY_ALIGNMENT;
      }

      assert(0 == size_t(my_AllocPtr) % MY_ALIGNMENT);     // Test invariant

      return result;
  }
Below, we use our allocation function to allocate arrays of char, short, and user-defined Object types from the static buffer. Note that our Object structure is composed of members that have alignment requirements less than or equal to ints alignment requirements.
  struct Object {
      char  d_c;
      short d_s;
      int   d_i;
  };

  int main()
  {
      // Allocate three 'char's from the buffer.
      char *charPtr   = (char *)   allocateFromBuffer(3 * sizeof(char));
      assert(0 == size_t(charPtr) % MY_ALIGNMENT);

      // Allocate three 'short's from the buffer.
      short *shortPtr = (short *)  allocateFromBuffer(3 * sizeof(short));
      assert(0 == size_t(shortPtr) % MY_ALIGNMENT);

      // Allocate three 'Object's from the buffer
      Object *objPtr = (Object *)  allocateFromBuffer(3 * sizeof(Object));
      assert(0 == size_t(objPtr) % MY_ALIGNMENT);

      if (!charPtr || !shortPtr || !objPtr) {
          fprintf(stderr, "Global buffer is not large enough.\n");
          return -1;
      }

      // ...

      return 0;
  }