|
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 usinggetAdaptedAllocator', 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.