BDE 4.14.0 Production release
|
Provide a protocol for memory allocators that support release
.
release
capabilityThis component provides a class
, bdlma::ManagedAllocator
, that extends the bslma::Allocator
protocol to allocators that support the ability to release
all memory currently allocated through the protocol back to the memory supplier of the derived concrete allocator object.
This section illustrates intended use of this component.
The bdlma::ManagedAllocator
interface is especially useful for allocators that are based on an underlying pooling mechanism (e.g., bdlma::Multipool
or bdlma::BufferedSequentialPool
). In particular, such an allocator that implements the bdlma::ManagedAllocator
interface can release, via the release
method, all outstanding (pooled) memory back to the underlying allocator making the memory available for subsequent reuse. Moreover, use of the release
method can also often render superfluous the running of destructors on the objects making use of a managed allocator. In this first usage example, we define the my_BufferAllocator
class, an allocator that implements the bdlma::ManagedAllocator
interface. my_BufferAllocator
is a considerably pared down version of bdlma::BufferedSequentialAllocator
, and is intended for illustration purposes only. Please see the bdlma_bufferedsequentialallocator component for full documentation of bdlma::BufferedSequentialAllocator
, a managed allocator meant for production use.
First, we define the interface of the my_BufferAllocator
class:
Next, we define the inline
methods of my_BufferAllocator
. Note that the release
method resets the internal cursor to 0, effectively making the memory from the entire external buffer supplied at construction available for subsequent allocations, but has no effect on the contents of the buffer:
Finally, we provide the implementation of the my_BufferAllocator
methods that are defined in the .cpp
file. A static
helper function, allocateFromBufferImp
, provides the bulk of the implementation of the allocate
method:
In this second usage example, we illustrate how the managed allocator that was defined in Example 1, my_BufferAllocator
, may be used. Note that substantial portions of the sample implementation are elided as they would only add unnecessary complications to the usage example. The portions shown are sufficient to illustrate the use of bdlma::ManagedAllocator
.
The domain of our example is financial markets. Suppose that we are given a list of market indices (e.g., Dow Jones Industrial Average, S&P 500, etc.), and we want to perform some computation on each index, in turn. In this example, the essential attributes of an index are held in a bsl::pair
consisting of the name of the index (e.g., "DJIA") and the number of securities that comprise the index (e.g., 30 in the case of the DJIA). The collection of market indices that we wish to process is given by a vector of such pairs. Thus, we make use of these types related to indices:
In our example, a security is defined by the unconstrained attribute type my_SecurityAttributes
, the interface and implementation of which is elided except we note that it uses bslma
allocators:
For the collection of securities comprising an index we use a vector of my_SecurityAttributes
:
Since some indices are quite large (e.g., Russell 3000, Wilshire 5000), for performance reasons it is advantageous for a SecurityCollection
to use an efficient memory allocation strategy. This is where my_BufferAllocator
comes into play, which we will see shortly.
The top-level function in our example takes a bdlma::ManagedAllocator *
and the collection of market indices that we wish to process:
processIndices
makes use of two helper functions to process each index:
Since we plan to use my_BufferAllocator
as our managed allocator, we need to supply it with an external buffer. The calculateMaxBufferSize
function computes the size of the buffer required to store the SecurityCollection
corresponding to the largest index to be processed by a given call to processIndices
:
Before showing the implementation of processIndices
, where the most interesting use of our managed allocator takes place, we show the site of the call to processIndices
.
First, assume that we have been given an IndexCollection
that has been populated with one or more IndexAttributes
:
Next, we calculate the size of the buffer that is needed, allocate the memory for the buffer from the default allocator, create our concrete managed allocator (namely, an instance of my_BufferAllocator
), and call processIndices
:
Next, we show the implementation of processIndices
, within which we iterate over the market indices
that are passed to it:
For each index, the SecurityCollection
comprising that index is created. All of the memory needs of the SecurityCollection
are provided by the managedAllocator
. Note that even the memory for the footprint of the collection comes from the managedAllocator
:
Next, we call loadIndex
to populate securities
, followed by the call to processIndex
. loadIndex
also uses the managedAllocator
, the details of which are not shown here:
After the index is processed, release
is called on the managed allocator making all of the buffer supplied to the allocator at construction available for reuse:
Finally, we let the SecurityCollection
used to process the index go out of scope intentionally without deleting securities
. The call to release
renders superfluous the need to call the SecurityCollection
destructor as well as the destructor of the contained my_SecurityAttributes
elements.