// bslma_rawdeleterguard.h                                            -*-C++-*-
#ifndef INCLUDED_BSLMA_RAWDELETERGUARD
#define INCLUDED_BSLMA_RAWDELETERGUARD

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a guard to unconditionally manage an object.
//
//@CLASSES:
//  bslma::RawDeleterGuard: guard to unconditionally manage an object
//
//@SEE_ALSO: bslma_rawdeleterproctor, bslma_autorawdeleter
//
//@DESCRIPTION: This component provides a guard class template,
// 'bslma::RawDeleterGuard', to unconditionally manage an (otherwise-unmanaged)
// object of parameterized 'TYPE' supplied at construction.  The managed object
// is deleted automatically when the guard 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.
//
///"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::RawDeleterGuard' 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
///-----
// This example shows how one might use a 'bslma::RawDeleterGuard' to guard a
// dynamically-allocated object, deleting that object automatically when the
// guard goes out of scope.
//
// Suppose we have a simple queue class that stores object values using an
// "out-of-place" representation (i.e., an array of dynamically-allocated
// object pointers):
//..
//  // my_queue.h
//  // ...
//
//  template <class TYPE>
//  class my_Queue {
//      // This class is a container that uses an "out-of-place"
//      // representation to manage objects of parameterized 'TYPE'.  Note
//      // that this class is implemented with the native version of 'deque',
//      // instead of the version provided in 'bslstl_Deque'.  This is so that
//      // a circular dependency in the physical hierarchy will not be created.
//
//      // DATA
//      std::deque<TYPE *>   d_objects;      // objects stored in the queue
//      bslma::Allocator    *d_allocator_p;  // allocator (held, not owned)
//
//    public:
//      // CREATORS
//      my_Queue(bslma::Allocator *basicAllocator = 0);
//          // Create a 'my_Queue' object.  Optionally specify a
//          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
//          // 0, the currently installed default allocator is used.
//
//      // ...
//
//      ~my_Queue();
//          // Destroy this 'my_Queue' object and all elements currently
//          // stored.
//
//      // MANIPULATORS
//
//      // ...
//
//      void pushBack(const TYPE& object);
//          // Push the value of the specified 'object' of parameterized 'TYPE'
//          // onto the back of this queue.
//
//      TYPE popFront();
//          // Remove and return (by value) the object of parameterized 'TYPE'
//          // that is currently at the front of this queue.
//
//      // ...
//  };
//..
// Note that the 'popFront' method returns an object by value because (1) there
// may be no reasonable default object to pass in, (2) there may be no
// reasonable copy-assignment semantics, or (3) it is simply more syntactically
// convenient (e.g., if, say, the queued objects are themselves pointers):
//..
//  // CREATORS
//  template <class TYPE>
//  inline
//  my_Queue<TYPE>::my_Queue(bslma::Allocator *basicAllocator)
//  : d_objects(basicAllocator)
//  , d_allocator_p(bslma::Default::allocator(basicAllocator))
//  {
//  }
//
//  template <class TYPE>
//  my_Queue<TYPE>::~my_Queue()
//  {
//      for (int i = 0; i < d_objects.size(); ++i) {
//          d_allocator_p->deleteObjectRaw(d_objects[i]);
//      }
//  }
//..
// Note that the 'pushBack' method should be implemented with a constructor
// proxy that determines whether 'TYPE' takes an allocator at construction (see
// 'bslalg_constructorproxy').  However, for the purpose of this example, the
// implementation is simplified by assuming 'TYPE' takes an allocator.
//..
//  // MANIPULATORS
//  template <class TYPE>
//  inline
//  void my_Queue<TYPE>::pushBack(const TYPE& object)
//  {
//      TYPE *tmp = (TYPE *)new(*d_allocator_p) TYPE(object);
//      d_objects.push_back(tmp);
//  }
//
//  template <class TYPE>
//  inline
//  TYPE my_Queue<TYPE>::popFront()
//  {
//      TYPE *tmp = d_objects.front();
//      d_objects.pop_front();
//
//      //***********************************************************
//      //* Note the use of the raw deleter guard on 'tmp' (below). *
//      //***********************************************************
//
//      bslma::RawDeleterGuard<TYPE, bslma::Allocator>
//                                                   guard(tmp, d_allocator_p);
//
//      return *tmp;
//  }
//..
// The 'pushBack' method defined above stores a copy of the provided object.
// The 'popFront' method returns the leading object by value, and the
// 'bslma::RawDeleterGuard' is used to automatically delete the copy the queue
// manages when the guard goes out of scope (i.e., when the function returns).

#include <bslscm_version.h>

#include <bslma_deleterhelper.h>

#include <bsls_assert.h>

namespace BloombergLP {

namespace bslma {

                        // =====================
                        // class RawDeleterGuard
                        // =====================

template <class TYPE, class ALLOCATOR>
class RawDeleterGuard {
    // This class implements a guard that unconditionally deletes a managed
    // object upon destruction by first invoking the object's destructor, and
    // then invoking the 'deallocate' method of an allocator (or pool) of
    // parameterized 'ALLOCATOR' type supplied to it at construction.  The
    // managed object of parameterized 'TYPE' must have been created using
    // memory provided by this allocator (or pool), which must remain valid
    // throughout the lifetime of the guard object.

    // DATA
    TYPE      *d_object_p;     // managed object
    ALLOCATOR *d_allocator_p;  // allocator or pool (held, not owned)

    // NOT IMPLEMENTED
    RawDeleterGuard(const RawDeleterGuard&);
    RawDeleterGuard& operator=(const RawDeleterGuard&);

  public:
    // CREATORS
    RawDeleterGuard(TYPE *object, ALLOCATOR *allocator);
        // Create a raw deleter guard that unconditionally manages the
        // specified 'object', and that uses the specified 'allocator' to
        // delete 'object' upon the destruction of this guard.  The behavior is
        // undefined unless 'object' and 'allocator' are non-zero, and
        // 'allocator' supplied the memory for 'object'.  Note that 'allocator'
        // must remain valid throughout the lifetime of this guard.

    ~RawDeleterGuard();
        // Destroy this raw deleter guard and delete the object it manages by
        // first invoking the destructor of the (managed) object, and then
        // invoking the 'deallocate' method of the allocator (or pool) that was
        // supplied with the object at construction.
};

// ============================================================================
//                          INLINE DEFINITIONS
// ============================================================================

                        // ---------------------
                        // class RawDeleterGuard
                        // ---------------------

// CREATORS
template <class TYPE, class ALLOCATOR>
inline
RawDeleterGuard<TYPE, ALLOCATOR>::
RawDeleterGuard(TYPE *object, ALLOCATOR *allocator)
: d_object_p(object)
, d_allocator_p(allocator)
{
    BSLS_ASSERT_SAFE(object);
    BSLS_ASSERT_SAFE(allocator);
}

template <class TYPE, class ALLOCATOR>
inline
RawDeleterGuard<TYPE, ALLOCATOR>::~RawDeleterGuard()
{
    BSLS_ASSERT_SAFE(d_object_p);
    BSLS_ASSERT_SAFE(d_allocator_p);

    DeleterHelper::deleteObjectRaw(d_object_p, d_allocator_p);
}

}  // close package namespace

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#ifdef bslma_RawDeleterGuard
#undef bslma_RawDeleterGuard
#endif
#define bslma_RawDeleterGuard bslma::RawDeleterGuard
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------