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

Detailed Description

Outline

Purpose

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

Classes

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:

,------------------------.
`------------------------'
| ctor/dtor
|
V
,----------------.
( bslma::Allocator )
`----------------'
allocate
deallocate
Definition bdlma_aligningallocator.h:232

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;
}
}
Definition bslma_allocator.h:457
virtual void * allocate(size_type size)=0

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);
Definition bdlma_bufferedsequentialallocator.h:265

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);
Definition bsls_alignmentfromtype.h:376

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;
}
}
}