BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslma_rawdeleterproctor

Detailed Description

Outline

Purpose

Provide a proctor to conditionally manage an object.

Classes

See also
bslma_rawdeleterguard, bslma_autorawdeleter

Description

This component provides a proctor class template, bslma::RawDeleterProctor, to conditionally manage an (otherwise-unmanaged) object of parameterized TYPE supplied at construction. If not explicitly released, the managed object is deleted automatically when the proctor object goes out of scope by first calling the (managed) object's destructor, and then freeing the memory using the parameterized ALLOCATOR (allocator or pool) also supplied at construction. Note that after a proctor object releases its managed object, the same proctor can be reused to conditionally manage another object (allocated from the same allocator or pool that was supplied at construction) by invoking the reset method.

"Raw" Warning

Note that this component should be used only if we are sure that the supplied pointer is not of a type that is a secondary base class – i.e., the (managed) object's address is (numerically) the same as when it was originally dispensed by ALLOCATOR.

Requirement

The parameterized ALLOCATOR type of the bslma::RawDeleterProctor class template must provide a (possibly virtual) method:

void deallocate(void *address);

to deallocate memory at the specified address (originally supplied by the ALLOCATOR object).

Usage

bslma::RawDeleterProctor is normally used to achieve exception safety in an exception neutral way by managing objects that are created temporarily on the heap, but not yet committed to a container object's management. This (somewhat contrived) example illustrates the use of a bslma::RawDeleterProctor to manage a dynamically-allocated object, deleting the object automatically should an exception occur.

Suppose we have a simple linked list class that manages objects of parameterized TYPE, but which are (for the purpose of this example) allocated separately from the links that hold them (thereby requiring two separate allocations for each append operation):

// my_list.h
// ...
template <class TYPE>
class my_List {
// This class is a container that uses a linked list data structure to
// manage objects of parameterized 'TYPE'.
// PRIVATE TYPES
struct Link {
TYPE *d_object_p; // object held by the link
Link *d_next_p; // next link
};
// DATA
Link *d_head_p; // head of list
Link *d_tail_p; // tail of list
int d_length; // number of objects
bslma::Allocator *d_allocator_p; // allocator (held, not owned)
public:
// CREATORS
my_List(bslma::Allocator *basicAllocator = 0);
// Create a 'my_List' object having an initial length of 0.
// Optionally specify a 'basicAllocator' used to supply memory. If
// 'basicAllocator' is 0, the currently installed default allocator
// is used.
// ...
~my_List();
// Destroy this 'my_List' object and all elements currently stored.
// MANIPULATORS
// ...
void append(const TYPE& object);
// Append (a copy of) the specified 'object' of parameterized
// 'TYPE' to (the end of) this list.
// ...
};
Definition bslma_allocator.h:457

Note that the rest of the my_List interface (above) and implementation (below) are omitted as the portion shown is sufficient to demonstrate the use of bslma::RawDeleterProctor.

// CREATORS
template <class TYPE>
inline
my_List<TYPE>::my_List(bslma::Allocator *basicAllocator)
: d_head_p(0)
, d_tail_p(0)
, d_length(0)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
}
template <class TYPE>
my_List<TYPE>::~my_List()
{
while (d_head_p) {
Link *tmp = d_head_p;
d_head_p = d_head_p->d_next_p;
d_allocator_p->deleteObject(tmp->d_object_p);
d_allocator_p->deallocate(tmp);
}
}
// MANIPULATORS
template <class TYPE>
void my_List<TYPE>::append(const TYPE& object)
{
TYPE *tmp = (TYPE *)new(*d_allocator_p) TYPE(object, d_allocator_p);
// possibly throw
//************************************************************
// Note the use of the raw deleter proctor on 'tmp' (below). *
//************************************************************
d_allocator_p);
if (!d_head_p) {
d_head_p = new(*d_allocator_p) Link; // possibly throw
d_tail_p = d_head_p;
}
else {
d_tail_p->d_next_p = new(*d_allocator_p) Link; // possibly throw
d_tail_p = d_tail_p->d_next_p;
}
d_tail_p->d_object_p = tmp;
d_tail_p->d_next_p = 0;
//*********************************************************
// Note that the raw deleter proctor is released (below). *
//*********************************************************
proctor.release();
}
Definition bslma_rawdeleterproctor.h:242
Definition balxml_encoderoptions.h:68

The append method defined above potentially throws in three places. If the memory allocator held in d_allocator_p were to throw while attempting to create the object of parameterized TYPE, no memory would be leaked. But without subsequent use of the bslma::RawDeleterProctor, if the allocator subsequently throws while creating the link, all memory (and any other resources) acquired as a result of copying the (not-yet-managed) object would be leaked. Using the bslma::RawDeleterProctor prevents the leaks by deleting the proctored object automatically should the proctor go out of scope before the release method of the proctor is called (such as when the function exits prematurely due to an exception).

Note that the append method assumes the copy constructor of TYPE takes an allocator as a second argument. In production code, a constructor proxy that checks the traits of TYPE (to determine whether TYPE uses bslma::Allocator) should be used (see bslalg_constructorproxy ).