BDE 4.14.0 Production release
|
Provide an allocator interface for bsl::memory_resource
objects.
Canonical header: bsl_memory_resource.h
This component provides an STL-compatible proxy for any resource class derived from bsl::memory_resource
. The bsl::polymorphic_allocator
interface is identical to that of std::pmr::polymorphic_allocator
from the C++17 Standard Library; in fact, the former type is an alias for the latter type when using a C++17 or later library supplied by the platform.
The proxy class, bsl::polymorphic_allocator
is a template that adheres to the allocator requirements defined in section [allocator.requirements] of the C++ standard. bsl::polymorphic_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. A bsl::polymorphic_allocator
object is initialized using a pointer to a resource object derived from bsl::memory_resource
. Different types of memory resources use different allocation mechanisms, so this approach gives the programmer run time control over how the container obtains memory.
A container constructs its elements by calling the construct
method on its allocator. Importantly, bsl::polymorphic_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 the allocator type). Thus, a container instantiated with a scoped allocator ensures that its elements use the same allocator as the container itself.
A container using bsl::polymorphic_allocator
should not copy its allocator on assignment and thus, to avoid errors, bsl::polymorphic_allocator
, is not assignable. By design, a member of type bsl::polymorphic_allocator
will prevent the client class from having a compiler-generated (defaulted) assignment operator because such an assignment operator would almost certainly do the wrong thing – copying the allocator and allocated objects instead of cloning those objects using the destination allocator. Once constructed, there is no straightforward way to rebind a bsl::polymorphic_allocator
to use a different resource.
Instantiations of bsl::polymorphic_allocator
have reference semantics. A bsl::polymorphic_allocator
object does not "own" the bslma::Allocator
with which it is initialized; copying a bsl::polymorphic_allocator
object does not copy its resource object and destroying a bsl::polymorphic_allocator
does not destroy its resource object. Two bsl::polymorphic_allocator
objects compare equal if and only if the resource objects they refer to compare equal.
Because it is immutable, non-assignable, and has reference semantics, a single bsl::polymorphic_allocator
object is safe for concurrent access by multiple threads if and only if the bsl::memory_resource
it references is safe for concurrent access from multiple threads. Separate objects of bsl::polymorphic_allocator
type may safely be used in separate threads if and only if the bsl::memory_resource
objects they reference are, themselves, safe for concurrent access.
This section illustrates intended use of this component.
In this example, we define a class template, Holder<TYPE>
, that holds a single instance of TYPE
on the heap. Holder
is designed such that its memory use can be customized by supplying an appropriate allocator. A holder object can be empty and it can be move-constructed even if TYPE
is not movable. In addition, the footprint of a Holder
object is the same (typically the size of 2 pointers), regardless of the size of TYPE
.
First, we create a CountingResource
class, derived from bsl::memory_resource
, that keeps track of the number of blocks of memory that were allocated from the resource but not yet returned to the resource; see usage example 1 in bslma_memoryresource .
Now we define our actual Holder
template with with data members to hold the memory allocator and a pointer to the contained object:
Next, we declare the constructors. Following the pattern for allocator-aware types used in BDE, the public interface contains an allocator_type
typedef that can be passed to each constructor.:
Next, we declare the manipulators and accessors, allowing a Holder
to be assigned and giving a client access to its value and allocator:
Next, we'll implement the first constructor, which creates an empty object; its only job is to store the allocator:
Next, we'll implement the second constructor, which allocates memory and constructs an object in it. The try
/catch
block is needed to free the memory in case the constructor for TYPE
throws and exception. An alternative implementation would use an RAII object to automatically free the memory in the case of an exception (see bslma_deallocatorproctor ):
Next, we'll implement a destructor that deletes the value object and deallocates the allocated memory:
Finally, we've implemented enough of Holder
to demonstrate its use. Below, we pass the CountingResource
from Example 1 to the constructors several Holder
objects. Each non-empty Holder
allocates one block of memory, which is reflected in the outstanding block count. Note that the address of the resource can be passed directly to the constructors because bsl::polymorphic_allocator
is implicitly convertible from bsl::memory_resource *
: