Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlma_aligningallocator
[Package bdlma]

Provide an allocator-wrapper to allocate with a minimum alignment. More...

Namespaces

namespace  bdlma

Detailed Description

Outline
Purpose:
Provide an allocator-wrapper to allocate with a minimum alignment.
Classes:
bdlma::AligningAllocator wrapper to align memory allocation
See also:
Description:
This component defines a concrete allocator implementation, bdlma::AligningAllocator, providing the ability to allocate memory with a minimum alignment specified at the construction of the allocator. The following inheritance diagram shows the classes involved and their methods:
   ,------------------------.
  ( bdlma::AligningAllocator )
   `------------------------'
               |       ctor/dtor
               |
               V
       ,----------------.
      ( bslma::Allocator )
       `----------------'
                       allocate
                       deallocate
The AligningAllocator is supplied an allocator at construction, and ensures that memory returned by allocate meets a minimum alignment requirement. This may be useful in situations where a user needs to adapt an allocator supplying only natural alignment to software expecting an allocator with a higher alignment guarantee. The allocator supplied to an AligningAllocator at construction is held, not owned.
The allocator supplied to the aligning allocator must employ at least the natural alignment strategy (see bsls_alignment). Specifically, the aligning allocator will fail to properly align memory if the allocator passed to it employs the 1-byte alignment strategy.
Note that in order to provide the requested alignment an AligningAllocator will need to always overallocate memory from the underlying allocator. This can "waste" space equal to the alignment plus some extra bytes for bookkeeping information. For small allocations with large alignment values this waste can be very impactful. In general, this means this component should be used with small alignments or with larger allocations.
Usage:
This section illustrates intended use of this component.
Example 1: Using bdlma::AligningAllocator:
Suppose we are dealing with an externally supplied library function that creates a linked list of null-terminated strings, and we want to use a default-constructed buffered sequential allocator for memory allocation.
First, the externally supplied library defines the struct describing a node in the linked list:
  struct Node {
      // This 'struct' describes one node in a linked list containing
      // strings.

      Node *d_next;
      char  d_string[1];

      // CLASS METHODS
      static
      bsl::size_t sizeNeededForString(const char *string)
          // Return the size in bytes needed to store a 'Node' containing a
          // copy of the specified 'string'.
      {
          Node node;

          return sizeof(node.d_next) + bsl::strlen(string) + 1;
      }
  };
Then, the externally-supplied library defines the function that will create the linked list of nodes from a null-terminated array of pointers to C-strings:
  void externalPopulateStringList(Node             **head,
                                  const char       **stringArray,
                                  bslma::Allocator  *allocator)
      // Create a linked list of strings beginning with the specified '*head'
      // containing the null-terminated strings from the null-terminated
      // 'stringArray'.  Use the specified 'allocator' to supply memory.
  {
      *head = 0;
      const char *string;
      for (int ii = 0; 0 != (string = stringArray[ii]); ++ii) {
          Node *newNode = static_cast<Node *>(allocator->allocate(
                                     Node::sizeNeededForString(string)));
          assert(newNode != 0);

          bsl::strcpy(newNode->d_string, string);

          newNode->d_next = *head;
          *head = newNode;
      }
  }
Next, our example function will begin with the externally-supplied buffered sequential allocator that we are to use:
  void printFromNodes(bsl::ostream *out) {
      enum { k_BUFFER_SIZE = 4 * 1024 };
      char                               buffer4k[k_BUFFER_SIZE];
      bdlma::BufferedSequentialAllocator bsAlloc(buffer4k, k_BUFFER_SIZE);
There is a problem here, in that the nodes must be aligned by sizeof(Node *), but our buffered sequential allocator, like most BDE allocators, has a "natural alignment" strategy (see bsls_alignment), meaning that it infers the required alignment from the size of the allocation requested. This would normally give us properly aligned memory if we were allocating by sizeof(Node), but our Node objects are variable length, which will mislead the allocator to sometimes align the new segments by less than sizeof(Node *).
Then, we solve this problem by using an aligning allocator to wrap the buffered sequential allocator, ensuring that the memory will still come from the buffered sequential allocator, but nonetheless be aligned to the alignment requirement of Node.
      enum { k_ALIGNMENT = bsls::AlignmentFromType<Node>::VALUE };
      bdlma::AligningAllocator aligningAllocator(k_ALIGNMENT, &bsAlloc);
Next, we define a null-terminated array of strings we would like to store in the list:
      const char *strings[] = {
          "A zinger is not a rebuttal.\n",
          "Humor is mankind's greatest blessing.\n",
          "As usual, the facts don't care about our feelings.\n",
          "Criticism is the only antidote to error.\n",
          "If you can't annoy somebody, there is little point in writing.\n",
          "Maybe all one can do is hope to end up with the right regrets.\n",
          "People may hear your words, but they feel your attitude.\n",
          "Imagination is a poor substitute for experience.\n",
          "We wanted a labor force, but human beings came.\n",
          "The reward of a thing well done is to have done it.\n",
          "Chance fights ever on the side of the prudent.\n",
          "The best time to make friends is before you need them.\n",
          0  };
Now, we call the function to put the strings into a linked list, passing it the aligning allocator:
      Node *head = 0;
      externalPopulateStringList(&head, strings, &aligningAllocator);
Finally, we traverse the list and print out the strings, verifying that the nodes are properly aligned:
      for (const Node *node = head; node; node = node->d_next) {
          assert(0 == (reinterpret_cast<bsl::size_t>(node) &
                       (k_ALIGNMENT - 1)));
          if (out) {
              *out << node->d_string;
          }
      }
  }