BDE 4.14.0 Production release
|
Macros | |
#define | BSLMA_BSLALLOCATOR_DEPRECATE_ASSIGN |
Provide an STL-compatible proxy for bslma::Allocator
objects.
bsl::allocator
Canonical header: bsl_memory.h
This component provides an STL-compatible proxy for any allocator class derived from bslma::Allocator
. The proxy class, bsl::allocator
is a template that adheres to the allocator requirements defined in section 20.5.3.5 [allocator.requirements] of the C++17 standard. bsl::allocator
may be used to instantiate any class template that is parameterized by a standard allocator. The container is expected to allocate memory for its own use through the allocator. The bsl::allocator
object holds a pointer to an object (the allocation mechanism) of class type derived from bslma::Allocator
. Different mechanism types allocate memory in different ways or from different pools, so this approach gives the programmer run time control over how the container obtains memory.
The bsl::allocator
template is intended to solve a problem created by the C++ standard allocator protocol. In STL, the allocator type is specified at compile time as a container template parameter, so the allocation mechanism becomes an explicit part of the resulting container type. Two containers cannot have the same type unless they are instantiated with the same allocator type. The bsl::allocator
template breaks the connection between the compile-time allocator type and the run-time allocation mechanism. The allocation mechanism is chosen at run-time by initializing (contrast with instantiating) the bsl::allocator
with a pointer to a mechanism object derived from bslma::Allocator
. Each class derived from bslma::Allocator
implements a specific allocation mechanism and is thus called a mechanism class within this component. The bsl::allocator
object forwards calls made through the standard allocator interface to the mechanism object with which it was initialized. In this way, two containers instantiated with bsl::allocator
can use different allocation mechanisms even though they have the same compile-time type. The default mechanism object, if none is supplied to the bsl::allocator
constructor, is bslma::Default::defaultAllocator()
.
A container constructs its elements by calling the construct
method on its allocator. Importantly, bsl::allocator
is a scoped allocator – when its construct
method is called, the allocator passes itself to the constructor of the object being constructed (if that object is allocator aware (AA) and uses a compatible allocator type). Thus, a container instantiated with a scoped allocator ensures that its elements use the same allocator as the container itself. The bsl::allocator::construct
method will propagate the allocator not only to element types that use bsl::allocator
, but also to any types that use bslma::Allocator *
– i.e., all type for which the bslma::UsesBslmaAllocator
trait is true.
A container using bsl::allocator
should not copy its allocator on assignment and thus assignment of bsl::allocator
objects is almost always incorrect. Its base class, bsl::polymorphic_allocator
, is not assignable, in fact but, for compatibility with some existing code, assignment of bsl::allocator
must compile, but it is a precondition violation if the allocators being assigned are not already equal at run time (i.e., when assignment is a a no-op). The assignment operator is deprecated and might be removed in the future, once all existing uses have been excised.
Instantiations of bsl::allocator
have reference semantics. A bsl::allocator
object does not "own" the bslma::Allocator
with which it is initialized; copying a bsl::allocator
object does not copy its mechanism object and destroying a bsl::allocator
does not destroy its mechanism object. Two bsl::allocator
objects compare equal if and only if the mechanism objects they refer to compare equal.
The bsl::allocator
class template was the inspiration for the C++17 std::pmr::polymorphic_allocator
class template (section 23.12.3, [mem.poly.allocator.class] in the C++17 Standard) and bslma::Allocator
was the inspiration for the C++17 std::pmr::memory_resource
(section 23.12.2, mem.res.class] in the C++17 Standard). For compatibility with the C++17 standard, bsl::allocator
is derived from bsl::polymorphic_allocator
which, when using a C++17 library, is identical to std::pmr::polymorphic_allocator
. Similarly, bslma::Allocator
is derived from bsl::memory_resource
, which is identical to std::pmr::memory_resource
. These inheritance relationships ensure that a bsl::allocator
instance can be passed to any type that is instantiated with a std::pmr::polymorphic_allocator
, including pmr
containers from the platform library. Similarly, a pointer to bslma::Allocator
is implicitly convertible to both std::pmr::memory_resource *
and std::pmr::polymorphic_allocator
.
The allocator requirements section of the C++03 standard (section 20.1.5 [lib.allocator.requirements]) permits containers to assume that two allocators of the same type always compare equal, effectively limiting C++03 to stateless allocators. This assumption is incorrect for instantiations of bsl::allocator
. Therefore, for a container (or other facility) to use bsl::allocator
, it must operate correctly in the presence of non-equal bsl::allocator
objects. In practice, this means that a container cannot transfer ownership of allocated memory to another container unless the two containers use equal allocators. Older third-party templates that assume stateless allocators might not work correctly when instantiated with bsl::allocator
.
Because it is immutable, non-assignable, and has reference semantics, a single bsl::allocator
object is safe for concurrent access by multiple threads if and only if the bslma::Allocator
it references is safe for concurrent access from multiple threads. Separate objects of bsl::allocator
type may safely be used in separate threads if and only if the bslma::Allocator
objects they reference are, themselves, safe for concurrent access.
This section illustrates intended use of this component.
We first show how to define a container type parameterized with an STL-style allocator template parameter. To avoid issues concerning reallocation, dynamic growth, etc., we choose an array whose size is fixed at construction. Our array will accept any STL-compatible allocator; we do not assume as scoped allocator, which would dictate that we pass the allocator through to the parameterized T
contained type (see the bslma_allocator component and bslma_constructionutil package).
We begin by defining member variables to hold the allocator, length, and allocated array:
Then, we define the public interface:
Next, we define the first constructor, which uses the allocator's allocate
memory to obtain memory, then uses its construct
method to construct each element. To provide a uniform and future-proof interface, the standard way to call allocate
and construct
is indrectly though bsl::allocator_traits
. If ALLOC
is a bsl::allocator
object, then the construct
method will attempt to pass the allocator to the constructed elements. Note that exception safety has been sacrificed for simplicity of presentation; a production version of my_FixedSizeArray
would need to unwind any constructed elements and the allocation if an exception were thrown.
Next, we define the copy constructor, which initializes the allocator member but defers the rest of the work to the assignment operator:
Now we define the assignment operator, which allocates the array and copies elements from the rhs
array. Note, again, that we simplified the code by omitting exception-safety constructs.
Next, we define the destructor, which uses the allocator's destroy
method to destroy each element, then the allocator's deallocate
method to return memory to the allocator:
The equality and inequality operators simply compare the lengths and element values of the two arrays:
Now we can create array objects with different allocator mechanisms. First we create an array, a1
, using the default allocator and fill it with the values 1 .. 5
:
Finally, we create a copy of a1
using a test allocator. The values of a1
and a2
are equal, even though they have different allocation mechanisms. We verify that the test allocator was used to allocate the new array elements:
In this example, we use the FixedSizeArray
template defined in Example 1 and demonstrate how bsl::allocator
propagates itself to the elements it constructs, such that the container and its elements all use the same allocator.
First, we create a representative element class, MyType
, that allocates memory using the bslma::Allocator
protocol:
Now, we instantiate my_FixedSizeArray
using MyType
and verify that, when we provide the address of an allocator to the constructor of the container, the same address is passed to the constructor of the container's elements:
Next, we copy-construct the container and verify that the copy uses the default allocator, not the allocator from the original; moreover, we verify that the elements stored in the copy also use the default allocator.
Finally, we create a third array using the test allocator and use assignment to give it the same value as the second array. We then verify that the assignment did not modify the allocator of the lhs array and that the elements of the resulting copy use the same allocator as the lhs array:
#define BSLMA_BSLALLOCATOR_DEPRECATE_ASSIGN |