Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslma_rawdeleterproctor
[Package bslma]

Provide a proctor to conditionally manage an object. More...

Namespaces

namespace  bslma

Detailed Description

Outline
Purpose:
Provide a proctor to conditionally manage an object.
Classes:
bslma::RawDeleterProctor proctor to conditionally manage an object
See also:
Component bslma_rawdeleterguard, Component 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.

      // ...
  };
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). *
      //************************************************************

      bslma::RawDeleterProctor<TYPE, bslma::Allocator> proctor(tmp,
                                                             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();
  }
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).