BDE 4.14.0 Production release
|
Provide a proctor to conditionally unwind memory block allocation.
This component provides a proctor class template, bslma::DeallocateBytesProctor
, that conditionally reverses the effect of bslma::AllocatorUtil::allocateBytes(a, n, align)
or a->allocate(n)
, where a
is a memory resource or pool that allocates, n
is the number of bytes to allocate, and align is the desired alignment. Upon destruction, this proctor deallocates the block from the specified allocator or pool without calling any destructors. The proctor's constructor takes the same arguments as bslma::AllocatorUtil::deallocateBytes
, making it straightforward to allocate an object using allocateBytes
and protect it using DeallocateBytesProctor
.
As with all proctors, this class is used to automatically reclaim a resource in the event that a function ends prematurely, e.g., via an exception. After allocating a block of memory, an exception-safe function would create a DeallocateBytesProctor
to manage the new memory block. If the operation completes successfully, the code calls the proctor's release
method, which disengages the proctor. If, however, the function exits while the proctor is still engaged, the proctor's destructor will deallocate the managed memory block.
The DeallocateBytesProctor
template has one template parameter: the ALLOCATOR
type used to reclaim storage managed by the proctor. If ALLOCATOR
is a non-pointer type, the proctor uses bslma::AllocatorUtil::deallocateBytes(a, ptr, n, align)
to reclaim storage, where a
is the allocator, ptr
is the address of the managed memory block, n
is the number of managed bytes, and align
is an optional argument specifying the alignment of the block (max-aligned by default). Otherwise, if ALLOCATOR
is a pointer type, the proctor reclaims memory by calling a->deallocate(ptr)
. Instantiating DeallocateBytesProctor
with a pointer-type ALLOCATOR
is appropriate for classes derived from bslma::Allocator
and for BDE-style pool types, i.e., classes for which a->deallocate(ptr)
is well formed.
Example 1: Class having an owning pointer
In this example, we create a class, my_Manager
, having an owning pointer to an object of another class, my_Data
. Because it owns the my_Data
object, my_Manager
is responsible for allocating, constructing, deallocating, and destroying it.
First, we define the my_Data
class, which holds an integer value and counts how many times its constructor and destructor have been called. Its constructor will throw an exception if its integer argument equals the number of constructor calls before construction:
Next, we define my_Manager
as an allocator-aware class holding a pointer to my_Data
and maintaining its own count of constructor invocations:
Next, we define the constructor for my_Manager
, which begins by allocating a my_Data
object:
Then, the my_Manager
constructor constructs the my_Data
object in the allocated memory. However, as the constructor might throw, it first protects the data object with a bslma::DeallocateBytesProctor
:
Then, once the construct
operation completes successfully, we can release the data object from the proctor. Only then do we increment the construction count, as the constructor is now complete:
Next, we define the my_Manager
destructor, which destroys and deallocates its data object. Note that the arguments to deallocateBytes
is identical to the constructor arguments to the DeallocateBytesProctor
, above:
Now, we use a bslma::TestAllocator
to verify that, under normal (non exceptional) circumstances, constructing a my_Manager
object will result in one block of memory being allocated and one invocation of the my_Data
constructor:
Finally, when the my_Data
constructor does throw, a block is allocated but we verify that the my_Manager
constructor did not complete and that the block is automatically deallocated, resulting in no leaks: