BDE 4.14.0 Production release
|
Provide a uniform interface to standard allocator types.
TBD: update component-level doc
The standard allocator_traits
class template is defined in the C++11 standard ([allocator.traits]) as a uniform mechanism for accessing nested types within, and operations on, any standard-conforming allocator. An allocator_traits
specialization is stateless, and all of its member functions are static. In most cases, facilities of allocator_traits
are straight pass-throughs for the same facilities from the ALLOC
template parameter. For example, allocator_traits<X>::pointer
is the same as X::pointer
and allocator_traits<X>::allocate(x, n)
is the same as x.allocate(n)
. The advantage of using allocator_traits
instead of directly using the allocator is that the allocator_traits
interface can supply parts of the interface that are missing from ALLOC
. In fact, the most important purpose of allocator_traits
is to provide implementations of C++11 allocator features that were absent in C++03, thus allowing a C++03 allocator to work with C++11 containers.
This component provides a full C++11 interface for allocator_traits
, but constrains the set of allocator types on which it may be instantiated. Specifically, this implementation does not provide defaults for C++03 types and functions, and has hard-wired implementations of the new C++11 features. Thus, the allocator_traits
template cannot be instantiated on an allocator type that does not provide a full compliment of types and functions required by the C++03 standard, and it will ignore any special C++11 features specified in ALLOC
. This limitation exists because Bloomberg does not need the full functionality of the C++11 model, but needs only to distinguish between C++03 allocators and allocators that implement the BSLMA allocator model (see bslma_bslallocator ). The full feature set of allocator_traits
would require a lot of resources for implementation and (especially) testing. Moreover, a full implementation would require metaprogramming that is too advanced for the feature set of the compilers currently in use at Bloomberg. This interface is useful, however, as a way to future-proof containers against the eventual implementation of the full feature set, and to take advantage of the Bloomberg-specific features described below.
There are two important (new) C++11 features provided by the allocator_traits
interface: the construct
function having a variable-length argument list (limited to 5 constructor arguments on compilers that don't support variadic templates) and the allocator-propagation traits. The implementations of these features within this component are tuned to Bloomberg's needs. The construct
member function will automatically forward the allocator to the constructed object iff the ALLOC
parameter is convertible from bslma::Allocator*
and the object being constructed has the bslma::UsesBslmaAllocator
type trait, as per standard Bloomberg practice. The select_on_container_copy_construction
static member will return a default-constructed allocator iff ALLOC
is convertible from bslma::Allocator *
because bslma allocators should not be copied when a container is copy-constructed; otherwise this function will return a copy of the allocator, as per C++03 container rules. The other propagation traits all have a false
value, so allocators are not propagated on assignment or swap.
Note that use of this component will differ from a strict following of the C++03 standard, as the construct
and destroy
methods of the parameterized allocator type will not be called. Rather, the target object will always be constructed at the address specified by the user, by calling the constructor in-place. Similarly, the destructor will always be called directly, rather than using a parameterized allocator's destroy
method. Otherwise, this implementation will fully support the C++03 model, including use of allocators returning "smart pointers" from allocate
.
In this section we show intended usage of this component.
This example demonstrates the intended use of allocator_traits
to implement a standard-conforming container class. First, we create a container class that holds a single object and which meets the requirements both of a standard container and of a Bloomberg container. I.e., when instantiated with an allocator argument it uses the standard allocator model; otherwise it uses the bslma
model. We provide an alias, AllocTraits
, to the specific allocator_traits
instantiation to simplify the implementation of each method that must allocate memory, or create or destroy elements.
Next we define the type traits for MyContainer
so that it is recognized as an STL sequence container:
bslma
allocators if the ALLOC
template parameter is convertible from bslma::Allocator*
. TYPE
object in the allocated memory. Because the allocation and construction are done in two separate steps, we need to create a proctor that will deallocate the allocated memory in case the constructor throws an exception. The proctor uses the uniform interface provided by allocator_traits
to access the pointer
and deallocate
members of ALLOC
: allocate
and construct
members of allocator_traits
, which provide the correct semantic for passing the allocator to the constructed object when appropriate: MyContainer
needs to conditionally copy the allocator from the other
container. The copy constructor uses allocator_traits::select_on_container_copy_construction
to decide whether to copy the other
allocator (for non-bslma allocators) or to default-construct the allocator (for bslma allocators). allocator_traits
functions to destroy and deallocate the value object: MyContainer
, instantiating it with element type int
: This example shows that when MyContainer
is instantiated with a C++03 allocator, that the allocator is a) copied on copy construction and b) is not propagated from the container to its elements. Firstly we create a representative element class, MyType
, that allocates memory using the bslma allocator protocol:
Then we create a C++03-style allocator class template:
Finally we instantiate MyContainer
using this allocator type and verify that elements are constructed using the default allocator (because the allocator is not propagated from the container). We also verify that the allocator is copied on copy-construction: