BDE 4.14.0 Production release
|
Provide a namespace for utility functions on allocator-aware types.
This component provides a namespace struct
, bslma::AATypeUtil
, that provides functions for extracting the allocator from an allocator-aware (AA) type. The functions in this struct
choose the appropriate machinery to get the allocator from an object of a specified TYPE
based on the AA model supported by TYPE
. For example, if AAModel<TYPE>
is AAModelLegacy
(see bslma_aamodel ), then the allocator is extracted using the allocator
mechanism. Some of the methods in this component are used to request allocators of a specific type; if the object's allocator is not convertible to that type, then the program will not compile.
This example illustrates how bslma::AATypeUtil::getAdaptedAllocator
can be used to extract the allocator from an Allocator-Aware (AA) object and use it to construct a different AA object without regard to whether either object is legacy-AA (using bslma::Allocator *
) or bsl-AA (using bsl::allocator
). We begin by defining two legacy-AA classes, Larry
, and Curly
:
Next, consider a class, LarryMaybeCurly
, that holds a Larry
object and optionally, holds a Curly
object. The data members for LarryMaybeCurly
include a Larry
object, a flag indicating the existence of a Curly
object, and an aligned buffer to hold the optional Curly
object, if it exists. Because the Larry
member holds an allocator, there is no need for a separate allocator data member:
Next we complete the public interface, which includes a constructor that sets the value of the Larry
object, a manipulator for setting the value of the Curly
object, and accessors for retrieving the Larry
and Curly
objects. Because LarryMaybeCurly
is allocator-aware (AA), we must have an allocator_type
member, and a get_allocator accessor; every constructor should also take an optional allocator argument.
Now we implement the constructor that initializes value of the Larry
member and leaves the Curly
member unset. Notice that we use bslma::AllocatorUtil::adapt
to smooth out the mismatch between the bsl::allocator
used by LarryMaybeCurly
and the bslma::Allocator *
expected by Larry
.
Next, we implement the manipulator for setting the Curly
object. This manipulator must use the allocator stored in d_larry
. The function, getAdaptedAllocator
yields this allocator in a form that can be consumed by the Curly
constructor:
Finally, we can use a test allocator to verify that, when a LarryMaybeCurly
object is constructed with an allocator, that same allocator is used to construct both the Larry
and Curly
objects within it:
It may not be immediately obvious that getAdaptedAllocator
provides much benefit; indeed, the example would work just fine if we called Larry::allocator()
and passed the result directly to the constructor of Curly
:
The code above is brittle, however, as updating Larry
to be bsl-AA would require calling larryObj.get_allocator().mechanism()
instead of larryObj.allocator(). By using
getAdaptedAllocator', the setCurly
implementation above is robust in the face of such future evolution. This benefit is even more important in generic code.
This example illustrates how bslma::AATypeUtil::getAllocatorFromSubobject
can be used to retrieve an allocator of a specific type from a subobject even if that subobject uses an allocator with a smaller interface.
First, continuing from the previous example, we implement the get_allocator accessor. As we know, the allocator for a LarryMaybeCurly
object is stored in the d_larry
subobject, obviating a separate d_allocator_p
member. However, the allocator within d_larry
is a bslma::Allocator *
whereas the allocator_type
for LarryMaybeCurly
is bsl::allocator<char>
. When the LarryMaybeCurly
object was constructed, some type information was lost in the conversion to bslma::Allocator
. That information is recovered through the use of getAllocatorFromSubobject
:
Now we can construct a LarryMaybeCurly
object with a specific allocator and recover that allocator using the get_allocator accessor:
As in the previous example, it is possible to get the same effect without using the utilities in this component because bslma::Allocator *
is implicitly convertible to bsl::allocator<char>
:
However, the preceding get_allocator implementation, like the setCurly
implementation in the previous example, is more robust because it need not be changed if Larry
is changed from legacy-AA to bsl-AA or if it is replaced by a template parameter that might use either AA model or even the pmr-AA model. Using the getAllocatorFromSubobject
idiom is, in fact, vital to recovering bsl
allocators stored within pmr-AA objects.