BDE 4.14.0 Production release
|
Provide a proctor to conditionally unwind new object creation.
This component provides a proctor class template, bslma::DeleteObjectProctor
, that conditionally reverses the effect of bslma::AllocatorUtil::newObject<TYPE>
or new (bslmAllocator) TYPE
. Upon destruction, this proctor invokes the TYPE
destructor and deallocates the object from the specified allocator or pool. The proctor's constructor takes the same arguments as bslma::AllocatorUtil::deleteObject
, making it straightforward to allocate an object using newObject
and protect it using DeleteObjectProctor
.
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 and constructing an object, an exception-safe function would create a DeleteObjectProctor
to manage the new object's lifetime. If the operation completes successfully, the code calls the proctor's release
method, which disengages the proctor. If, however, the function or constructor exits while the proctor is still engaged, the proctor's destructor will destroy and deallocate the managed object.
The DeleteObjectProctor
template has two template parameters: the ALLOCATOR
type used to reclaim storage and the object TYPE
managed by the proctor. If ALLOCATOR
is a non-pointer type and TYPE
is omitted, it is deduced as ALLOCATOR::value_type
. However, if TYPE
is supplied, it overrides ALLOCATOR::value_type
.
If ALLOCATOR
is a non-pointer type, the proctor uses bslma::AllocatorUtil::deleteObject(a, ptr)
to destroy the managed object and reclaim its storage, where a
is the allocator, and ptr
is the address of the managed object. Otherwise, if ALLOCATOR
is a pointer type, the proctor invokes the TYPE
destructor followed by a->deallocate(ptr)
. Instantiating DeleteObjectProctor
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.
These examples illustrate the intended use of this component.
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. It also has a manipulator, mightThrow
, that throws an exception if the integer value equals the number of constructor calls:
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 and constructing a my_Data
object:
Then, the my_Manager
constructor invokes the mightThrow
manipulator on the new data object, but first, it protects the object with a bslma::DeleteObjectProctor
:
Then, once the mightThrow
operation completes successfully, we can release the data object from the proctor. Only then do we increment the construction count:
Next, we define the my_Manager
destructor, which destroys and deallocates its data object:
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 mightThrow
does throw, a block is allocated and a my_Data
constructor is invoked, but we verify that the my_Manager
constructor did not complete, the my_Data
destructor was called and the block was deallocated, resulting in no leaks: