// bslma_managedptr.h                                                 -*-C++-*-
#ifndef INCLUDED_BSLMA_MANAGEDPTR
#define INCLUDED_BSLMA_MANAGEDPTR

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

//@PURPOSE: Provide a managed pointer class.
//
//@CLASSES:
//  bslma::ManagedPtr: proctor for automatic memory management
//  bslma::ManagedPtrUtil: namespace for `ManagedPtr`-related utility functions
//
//@SEE_ALSO: bslmf_ispolymporphic
//
//@DESCRIPTION: This component provides a proctor, `bslma::ManagedPtr`, similar
// to `bsl::auto_ptr`, that supports user-specified deleters.  The proctor is
// responsible for the automatic destruction of the object referenced by the
// managed pointer.  As a "smart pointer", this object offers an interface
// similar to a native pointer, supporting dereference operators (*, ->),
// (in)equality comparison and testing as if it were a boolean value.  However,
// like `bsl::auto_ptr` it has unusual "copy-semantics" that transfer ownership
// of the managed object, rather than making a copy.  It should be noted that
// this signature does not satisfy the requirements for an element-type stored
// in any of the standard library containers.  Note that this component will
// fail to compile when instantiated for a class that gives a false-positive
// for the type trait `bslmf::IsPolymorphic`.  See the `bslmf_ispolymporphic`
// component for more details.
//
// This component also provides the `bslma::ManagedPtrUtil` `struct`, which
// defines a namespace for utility functions that facilitate working with
// `ManagedPtr` objects.  Of particular note are the `allocateManaged` and
// `makeManaged` class methods that can be used to create a managed object as
// well as a `ManagedPtr` to manage it, with the latter being returned.
// `allocateManaged` takes a `bslma::Allocator *` argument that is both (1)
// used to allocate the footprint of the managed object and (2) used by the
// managed object itself if it defines the `bslma::UsesBslmaAllocator` trait.
// `makeManaged` does not take a `bslma::Allocator *` argument and uses the
// default allocator to allocate the footprint of the managed object instead.
//
///Factories
///---------
// An object that will be managed by a `ManagedPtr` object is typically
// dynamically allocated and destroyed by a factory.  For the purposes of this,
// component, a factory is any class that provides a `deleteObject` function
// taking a single argument of the (pointer) type of the managed pointer.  The
// following is an example of a factory deleter:
// ```
// class my_Factory {
//
//    // . . .
//
//    // MANIPULATORS
//
//    /// Create a `my_Type` object.  Optionally specify a
//    /// `basicAllocator` used to supply memory.  If `basicAllocator` is
//    /// 0, the currently installed default allocator is used.
//    my_Type *createObject(bslma::Allocator *basicAllocator = 0);
//
//    /// Delete the specified `object`.
//    void deleteObject(my_Type *object);
// };
//
// class my_Allocator : public bslma::Allocator { /* ... */ };
// ```
// Note that `deleteObject` is provided by all `bslma` allocators and by any
// object that implements the `bdlma::Deleter` protocol.  Thus, any of these
// objects can be used as a factory deleter.  The purpose of this design is to
// allow `bslma` allocators and factories to be used seamlessly as deleters.
//
// Note that when the `ManagedPtr(MANAGED_TYPE *)` constructor is used, the
// managed object will be destroyed with a built-in deleter that calls
// `delete ptr`, but when the `ManagedPtr(MANAGED_TYPE *, FACTORY_TYPE *)`
// constructor is called with `0 == factory`, the currently installed default
// allocator will be used as the factory.
//
///Deleters
///--------
// When a managed pointer is destroyed, the managed object is destroyed using
// the user supplied "deleter".  A deleter is simply a function that is invoked
// with two `void *` arguments: a pointer to the object to be destroyed, and a
// pointer to a `cookie` that is supplied at the same time as the `deleter` and
// managed object.
// ```
// typedef void (*DeleterFunc)(void *managedObject, void *cookie);
// ```
// The meaning of the `cookie` depends on the specific deleter.  Typically a
// deleter function will accept the two `void *` pointers and internally cast
// them to the appropriate types for pointers to the managed object and
// `cookie`.  Note that there are no methods taking just a deleter, as the user
// must always supply a `cookie` to be passed when the deleter is actually
// invoked.
//
// Note that this component still supports (deprecated) legacy deleters that
// expect to be passed pointers to the specific `cookie` and managed object
// types in use.  This latter form of deleter was deprecated as it relies on
// undefined behavior, casting such function pointers to the correct form
// (taking two `void *` arguments) and invoking the function with two `void *`
// pointer arguments.  While this is undefined behavior, it is known to have
// the desired effect on all platforms currently in use.
//
///Aliasing
///--------
// In a managed pointer, the pointer value (the value returned by the `get`
// method) and the pointer to the managed object need not have the same value.
// The `loadAlias` method allows a managed pointer to be created as an "alias"
// to another managed pointer (possibly of a different type), which we'll call
// the "original" managed pointer.  When `get` is invoked on the alias, the
// aliased pointer value is returned, but when the managed pointer is
// destroyed, the original managed object will be passed to the deleter.  (See
// also the documentation of the `alias` constructor or of the `loadAlias`
// method.)
//
///Exception Safety
///----------------
// The principal usage of a managed pointer is to guarantee that a local object
// will be deallocated properly should an operation throw after its allocation.
// In this, it is very similar to `bsl::auto_ptr`.  It is required for the
// proper functioning of this component that a deleter does not throw at
// invocation (upon destruction or re-assignment of the managed pointer).
//
///Type Casting
///------------
// `ManagedPtr` objects can be implicitly and explicitly cast to different
// types in the same way that native pointers can.
//
///Explicit Casting
/// - - - - - - - -
// Through "aliasing", a managed pointer of any type can be explicitly cast to
// a managed pointer of any other type using any legal cast expression.  See
// example 4 on `type casting` below for more details.
//
///Implicit Casting
/// - - - - - - - -
// As with native pointers, a managed pointer of the type `B` that is derived
// from the type `A`, can be directly assigned to a `ManagedPtr` of `A`.
// Likewise a managed pointer of type `B` can be directly assigned to a
// `ManagedPtr` of `const B`.  However, the rules for construction are a little
// more subtle, and apply when passing a `bslma::ManagedPtr` by value into a
// function, or returning as the result of a function.
// ```
// class A {};
//
// class B : public A {};
//
// void test()
// {
//     B *b_p = 0;
//     A *a_p = b_p;
//
//     bslma::ManagedPtr<B> b_mp1;
//     bslma::ManagedPtr<A> a_mp1(b_mp1);   // direct-initialization is valid
//     bslma::ManagedPtr<A> a_mp2 = b_mp1;  // copy-initialization should fail
// }
// ```
// Note that `std::auto_ptr` has the same restriction, and this failure will
// occur only on compilers that strictly conform to the C++ standard, such as
// recent gcc compilers or (in this case) IBM xlC.
//
///Usage
///-----
// In this section we show intended usage of this component.
//
///Example 1: Implementing a Protocol
/// - - - - - - - - - - - - - - - - -
// We demonstrate using `ManagedPtr` to configure and return a managed object
// implementing an abstract protocol.
//
// First we define our protocol, `Shape`, a type of object that knows how to
// compute its `area`.  Note that for expository reasons only, we do *not* give
// `Shape` a virtual destructor.
// ```
// struct Shape {
//     /// Return the `area` of this shape.
//     virtual double area() const = 0;
// };
// ```
// Then we define a couple of classes that implement the `Shape` protocol, a
// `Circle` and a `Square`.
// ```
// class Circle : public Shape {
//   private:
//     // DATA
//     double d_radius;
//
//   public:
//     // CREATORS
//
//     /// Create a `Circle` object having the specified `radius`.
//     explicit Circle(double radius);
//
//     /// Destroy this object.
//     virtual ~Circle();
//
//     // ACCESSORS
//
//     /// Return the area of this Circle, given by the formula pi*r*r.
//     virtual double area() const;
// };
//
// class Square : public Shape {
//   private:
//     // DATA
//     double d_sideLength;
//
//   public:
//     // CREATORS
//
//     /// Create a `Square` having sides of length `side`.
//     explicit Square(double side);
//
//     /// Destroy this object.
//     virtual ~Square();
//
//     // ACCESSORS
//
//     /// Return the area of this Square, given by the formula side*side
//     virtual double area() const;
// };
// ```
// Next we implement the methods for `Circle` and `Square`.
// ```
// Circle::Circle(double radius)
// : d_radius(radius)
// {
// }
//
// Circle::~Circle()
// {
// }
//
// double Circle::area() const {
//     return 3.141592653589793238462 * d_radius * d_radius;
// }
//
// Square::Square(double side)
// : d_sideLength(side)
// {
// }
//
// Square::~Square()
// {
// }
//
// double Square::area() const {
//     return d_sideLength * d_sideLength;
// }
// ```
// Then we define an enumeration that lists each implementation of the `Shape`
// protocol.
// ```
// struct Shapes {
//     enum VALUES { SHAPE_CIRCLE, SHAPE_SQUARE };
// };
// ```
// Now we can define a function that will return a `Circle` object or a
// `Square` object according to the specified `kind` parameter, and having its
// `dimension` specified by the caller.
// ```
// bslma::ManagedPtr<Shape> makeShape(Shapes::VALUES kind, double dimension)
// {
//     bslma::Allocator *alloc = bslma::Default::defaultAllocator();
//     bslma::ManagedPtr<Shape> result;
//     switch (kind) {
//       case Shapes::SHAPE_CIRCLE: {
//         Circle *circ = new(*alloc)Circle(dimension);
//         result.load(circ);
//       } break;
//       case Shapes::SHAPE_SQUARE: {
//         Square *sqr = new(*alloc)Square(dimension);
//         result.load(sqr);
//       } break;
//     }
//     return result;
// }
// ```
// Then, we can use our function to create shapes of different kinds, and check
// that they report the correct area.  Note that we are using a radius of `1.0`
// for the `Circle` and integral side-length for the `Square` to support an
// accurate `operator==` with floating-point quantities.  Also note that,
// despite the destructor for `Shape` being non-virtual, the correct destructor
// for the appropriate concrete `Shape` type is called.  This is because the
// destructor is captured when the `ManagedPtr` constructor is called, and has
// access to the complete type of each shape object.
// ```
// void testShapes()
// {
//     bslma::ManagedPtr<Shape> shape = makeShape(Shapes::SHAPE_CIRCLE, 1.0);
//     assert(0 != shape);
//     assert(3.141592653589793238462 == shape->area());
//
//     shape = makeShape(Shapes::SHAPE_SQUARE, 2.0);
//     assert(0 != shape);
//     assert(4.0 == shape->area());
// }
// ```
// Next, we observe that as we are creating objects dynamically, we should pass
// an allocator to the `makeShape` function, rather than simply accepting the
// default allocator each time.  Note that when we do this, we pass the user's
// allocator to the `ManagedPtr` object as the "factory".
// ```
// bslma::ManagedPtr<Shape> makeShape(Shapes::VALUES    kind,
//                                    double            dimension,
//                                    bslma::Allocator *allocator)
// {
//     bslma::Allocator *alloc = bslma::Default::allocator(allocator);
//     bslma::ManagedPtr<Shape> result;
//     switch (kind) {
//       case Shapes::SHAPE_CIRCLE: {
//         Circle *circ = new(*alloc)Circle(dimension);
//         result.load(circ, alloc);
//       } break;
//       case Shapes::SHAPE_SQUARE: {
//         Square *sqr = new(*alloc)Square(dimension);
//         result.load(sqr, alloc);
//       } break;
//     }
//     return result;
// }
// ```
// Finally we repeat the earlier test, additionally passing a test allocator:
// ```
// void testShapesToo()
// {
//     bslma::TestAllocator ta("object");
//
//     bslma::ManagedPtr<Shape> shape =
//                                  makeShape(Shapes::SHAPE_CIRCLE, 1.0, &ta);
//     assert(0 != shape);
//     assert(3.141592653589793238462 == shape->area());
//
//     shape = makeShape(Shapes::SHAPE_SQUARE, 3.0, &ta);
//     assert(0 != shape);
//     assert(9.0 == shape->area());
// }
// ```
//
///Example 2: Aliasing
///- - - - - - - - - -
// Suppose that we wish to give access to an item in a temporary array via a
// pointer, which we will call the "finger".  The finger is the only pointer to
// the array or any part of the array, but the entire array must be valid until
// the finger is destroyed, at which time the entire array must be deleted.  We
// handle this situation by first creating a managed pointer to the entire
// array, then creating an alias of that pointer for the finger.  The finger
// takes ownership of the array instance, and when the finger is destroyed, it
// is the array's address, rather than the finger, that is passed to the
// deleter.
//
// First, let's say our array stores data acquired from a ticker plant
// accessible by a global `getQuote` function:
// ```
// struct Ticker {
//
//     static double getQuote() // From ticker plant.  Simulated here
//     {
//         static const double QUOTES[] = {
//         7.25, 12.25, 11.40, 12.00, 15.50, 16.25, 18.75, 20.25, 19.25, 21.00
//         };
//         static const int NUM_QUOTES = sizeof(QUOTES) / sizeof(QUOTES[0]);
//         static int index = 0;
//
//         double ret = QUOTES[index];
//         index = (index + 1) % NUM_QUOTES;
//         return ret;
//     }
// };
// ```
// Then, we want to find the first quote larger than a specified threshold, but
// would also like to keep the earlier and later quotes for possible
// examination.  Our `getFirstQuoteLargerThan` function must allocate memory
// for an array of quotes (the threshold and its neighbors).  It thus returns a
// managed pointer to the desired value:
// ```
// const double END_QUOTE = -1;
//
// bslma::ManagedPtr<double> getFirstQuoteLargerThan(
//     double threshold,
//     bslma::Allocator *allocator)
// {
//     assert(END_QUOTE < 0 && 0 <= threshold);
// ```
// Next, we allocate our array with extra room to mark the beginning and end
// with a special `END_QUOTE` value:
// ```
//     const int MAX_QUOTES = 100;
//     int numBytes = (MAX_QUOTES + 2) * sizeof(double);
//     double *quotes = (double *) allocator->allocate(numBytes);
//     quotes[0] = quotes[MAX_QUOTES + 1] = END_QUOTE;
// ```
// Then, we create a managed pointer to the entire array:
// ```
//     bslma::ManagedPtr<double> managedQuotes(quotes, allocator);
// ```
// Next, we read quotes until the array is full, keeping track of the first
// quote that exceeds the threshold.
// ```
//     double *finger = 0;
//
//     for (int i = 1; i <= MAX_QUOTES; ++i) {
//         double quote = Ticker::getQuote();
//         quotes[i] = quote;
//         if (!finger && quote > threshold) {
//             finger = &quotes[i];
//         }
//     }
// ```
// Now, we use the alias constructor to create a managed pointer that points to
// the desired value (the finger) but manages the entire array:
// ```
//     return bslma::ManagedPtr<double>(managedQuotes, finger);
// }
// ```
// Then, our main program calls `getFirstQuoteLargerThan` like this:
// ```
// int aliasExample()
// {
//     bslma::TestAllocator ta;
//     bslma::ManagedPtr<double> result = getFirstQuoteLargerThan(16.00, &ta);
//     assert(*result > 16.00);
//     assert(1 == ta.numBlocksInUse());
//     if (g_verbose) bsl::cout << "Found quote: " << *result << bsl::endl;
// ```
// Next, we also print the preceding 5 quotes in last-to-first order:
// ```
//     if (g_verbose) bsl::cout << "Preceded by:";
//     int i;
//     for (i = -1; i >= -5; --i) {
//         double quote = result.get()[i];
//         if (END_QUOTE == quote) {
//             break;
//         }
//         assert(quote < *result);
//         if (g_verbose) bsl::cout << ' ' << quote;
//     }
//     if (g_verbose) bsl::cout << bsl::endl;
// ```
// Then, to move the finger, e.g., to the last position printed, one must be
// careful to retain the ownership of the entire array.  Using the statement
// `result.load(result.get()-i)` would be an error, because it would first
// compute the pointer value `result.get()-i` of the argument, then release the
// entire array before starting to manage what has now become an invalid
// pointer.  Instead, `result` must retain its ownership to the entire array,
// which can be attained by:
// ```
//     result.loadAlias(result, result.get()-i);
// ```
// Finally, if we reset the result pointer, the entire array is deallocated:
// ```
//     result.reset();
//     assert(0 == ta.numBlocksInUse());
//     assert(0 == ta.numBytesInUse());
//
//     return 0;
// }
// ```
//
///Example 3: Dynamic Objects and Factories
/// - - - - - - - - - - - - - - - - - - - -
// Suppose we want to track the number of objects currently managed by
// `ManagedPtr` objects.
//
// First we define a factory type that holds an allocator and a usage-counter.
// Note that such a type cannot sensibly be copied, as the notion `count`
// becomes confused.
// ```
// class CountedFactory {
//     // DATA
//     int               d_count;
//     bslma::Allocator *d_allocator_p;
//
//     // NOT IMPLEMENTED
//     CountedFactory(const CountedFactory&);
//     CountedFactory& operator=(const CountedFactory&);
//
//   public:
//     // CREATORS
//
//     /// Create a `CountedFactory` object which uses the supplied
//     /// allocator `alloc`.
//     explicit CountedFactory(bslma::Allocator *alloc = 0);
//
//     /// Destroy this object.
//     ~CountedFactory();
// ```
// Next, we provide the `createObject` and `deleteObject` functions that are
// standard for factory objects.  Note that the `deleteObject` function
// signature has the form required by `bslma::ManagedPtr` for a factory.
// ```
//     // MANIPULATORS
//
//     /// Return a pointer to a newly allocated object of type `TYPE`
//     /// created using its default constructor.  Memory for the object
//     /// is supplied by the allocator supplied to this factory's
//     /// constructor, and the count of valid object is incremented.
//     template <class TYPE>
//     TYPE *createObject();
//
//     /// Destroy the object pointed to by `target` and reclaim the
//     /// memory.  Decrement the count of currently valid objects.
//     template <class TYPE>
//     void deleteObject(const TYPE *target);
// ```
// Then, we round out the class with the ability to query the `count` of
// currently allocated objects.
// ```
//     // ACCESSORS
//     int count() const;
//         // Return the number of currently valid objects allocated by this
//         // factory.
// };
// ```
// Next, we define the operations declared by the class.
// ```
// CountedFactory::CountedFactory(bslma::Allocator *alloc)
// : d_count(0)
// , d_allocator_p(bslma::Default::allocator(alloc))
// {
// }
//
// CountedFactory::~CountedFactory()
// {
//     assert(0 == d_count);
// }
//
// template <class TYPE>
// TYPE *CountedFactory::createObject()
// {
//     TYPE *result = new(*d_allocator_p)TYPE;
//     ++d_count;
//     return result;
// }
//
// template <class TYPE>
// void CountedFactory::deleteObject(const TYPE *object)
// {
//     d_allocator_p->deleteObject(object);
//     --d_count;
// }
//
// inline
// int CountedFactory::count() const
// {
//     return d_count;
// }
// ```
// Then, we can create a test function to illustrate how such a factory would
// be used with `ManagedPtr`.
// ```
// void testCountedFactory()
// {
// ```
// Next, we declare a test allocator, and an object of our `CountedFactory`
// type using that allocator.
// ```
//     bslma::TestAllocator ta;
//     CountedFactory cf(&ta);
// ```
// Then, we open a new local scope and declare an array of managed pointers.
// We need a local scope in order to observe the behavior of the destructors at
// end of the scope, and use an array as an easy way to count more than one
// object.
// ```
//     {
//         bslma::ManagedPtr<int> pData[4];
// ```
// Next, we load each managed pointer in the array with a new `int` using our
// factory `cf` and assert that the factory `count` is correct after each new
// `int` is created.
// ```
//         int i = 0;
//         while (i != 4) {
//             pData[i++].load(cf.createObject<int>(), &cf);
//             assert(cf.count() == i);
//         }
// ```
// Then, we `reset` the contents of a single managed pointer in the array, and
// assert that the factory `count` is appropriately reduced.
// ```
//         pData[1].reset();
//         assert(3 == cf.count());
// ```
// Next, we `load` a managed pointer with another new `int` value, again using
// `cf` as the factory, and assert that the `count` of valid objects remains
// the same (destroy one object and add another).
// ```
//         pData[2].load(cf.createObject<int>(), &cf);
//         assert(3 == cf.count());
//     }
// ```
// Finally, we allow the array of managed pointers to go out of scope and
// confirm that when all managed objects are destroyed, the factory `count`
// falls to zero, and does not overshoot.
// ```
//     assert(0 == cf.count());
// }
// ```
//
///Example 4: Type Casting
///- - - - - - - - - - - -
// `ManagedPtr` objects can be implicitly and explicitly cast to different
// types in the same way that native pointers can.
//
///Implicit Conversion
///-  -  -  -  -  -  -
// As with native pointers, a pointer of the type `B` that is publicly derived
// from the type `A`, can be directly assigned a `ManagedPtr` of `A`.
//
// First, consider the following code snippets:
// ```
// void implicitCastingExample()
// {
// ```
// If the statements:
// ```
//     bslma::TestAllocator localDefaultTa;
//     bslma::TestAllocator localTa;
//
//     bslma::DefaultAllocatorGuard guard(&localDefaultTa);
//
//     int numdels = 0;
//
//     {
//         B *b_p = 0;
//         A *a_p = b_p;
// ```
// are legal expressions, then the statements
// ```
//         bslma::ManagedPtr<A> a_mp1;
//         bslma::ManagedPtr<B> b_mp1;
//
//         assert(!a_mp1 && !b_mp1);
//
//         a_mp1 = b_mp1;      // conversion assignment of nil ptr to nil
//         assert(!a_mp1 && !b_mp1);
//
//         B *b_p2 = new (localDefaultTa) B(&numdels);
//         bslma::ManagedPtr<B> b_mp2(b_p2);    // default allocator
//         assert(!a_mp1 && b_mp2);
//
//         a_mp1 = b_mp2;      // conversion assignment of non-nil ptr to nil
//         assert(a_mp1 && !b_mp2);
//
//         B *b_p3 = new (localTa) B(&numdels);
//         bslma::ManagedPtr<B> b_mp3(b_p3, &localTa);
//         assert(a_mp1 && b_mp3);
//
//         a_mp1 = b_mp3;      // conversion assignment of non-nil to non-nil
//         assert(a_mp1 && !b_mp3);
//
//         a_mp1 = b_mp3;      // conversion assignment of nil to non-nil
//         assert(!a_mp1 && !b_mp3);
//
//         // constructor conversion init with nil
//         bslma::ManagedPtr<A> a_mp4(b_mp3, b_mp3.get());
//         assert(!a_mp4 && !b_mp3);
//
//         // constructor conversion init with non-nil
//         B *p_b5 = new (localTa) B(&numdels);
//         bslma::ManagedPtr<B> b_mp5(p_b5, &localTa);
//         bslma::ManagedPtr<A> a_mp5(b_mp5, b_mp5.get());
//         assert(a_mp5 && !b_mp5);
//         assert(a_mp5.get() == p_b5);
//
//         // constructor conversion init with non-nil
//         B *p_b6 = new (localTa) B(&numdels);
//         bslma::ManagedPtr<B> b_mp6(p_b6, &localTa);
//         bslma::ManagedPtr<A> a_mp6(b_mp6);
//         assert(a_mp6 && !b_mp6);
//         assert(a_mp6.get() == p_b6);
//
//         struct S {
//             int d_i[10];
//         };
//
//         assert(200 == numdels);
//     }
//
//     assert(400 == numdels);
// } // implicitCastingExample()
// ```
//
///Explicit Conversion
///-  -  -  -  -  -  -
// Through "aliasing", a managed pointer of any type can be explicitly
// converted to a managed pointer of any other type using any legal cast
// expression.  For example, to static-cast a managed pointer of type A to a
// managed pointer of type B, one can simply do the following:
// ```
// void explicitCastingExample() {
//
//     bslma::ManagedPtr<A> a_mp;
//     bslma::ManagedPtr<B> b_mp1(a_mp, static_cast<B *>(a_mp.get()));
// ```
// or even use the less safe "C"-style casts:
// ```
//     bslma::ManagedPtr<B> b_mp2(a_mp, (B *)(a_mp.get()));
//
// } // explicitCastingExample()
// ```
// Note that when using dynamic cast, if the cast fails, the target managed
// pointer will be reset to an unset state, and the source will not be
// modified.  Consider for example the following snippet of code:
// ```
// void processPolymorphicObject(bslma::ManagedPtr<A> aPtr,
//                               bool *castSucceeded)
// {
//     bslma::ManagedPtr<B> bPtr(aPtr, dynamic_cast<B *>(aPtr.get()));
//     if (bPtr) {
//         assert(!aPtr);
//         *castSucceeded = true;
//     }
//     else {
//         assert(aPtr);
//         *castSucceeded = false;
//     }
// }
// ```
// If the value of `aPtr` can be dynamically cast to `B *` then ownership is
// transferred to `bPtr`; otherwise, `aPtr` is to be modified.  As previously
// stated, the managed object will be destroyed correctly regardless of how it
// is cast.
//
///Example 5: Inplace Object Creation
/// - - - - - - - - - - - - - - - - -
// Suppose we want to allocate memory for an object, construct it in place, and
// obtain a managed pointer referring to this object.  This can be done in one
// step using two free functions provided in `bslma::ManagedPtrUtil`.
//
// First, we create a simple class clearly showing the features of these
// functions.  Note that this class does not define the
// `bslma::UsesBslmaAllocator` trait.  It is done intentionally for
// illustration purposes only, and definitely is *not* *recommended* in
// production code.  The class has an elided interface (i.e., copy constructor
// and copy-assignment operator are not included for brevity):
// ```
// /// Simple class that stores a copy of a null-terminated C-style string.
// class String {
//
//   private:
//     // DATA
//     char             *d_str_p;    // stored value (owned)
//     bslma::Allocator *d_alloc_p;  // allocator to allocate any dynamic
//                                   // memory (held, not owned)
//
//   public:
//     // CREATORS
//
//     /// Create an object having the same value as the specified `str`
//     /// using the specified `alloc` to supply memory.
//     String(const char *str, bslma::Allocator *alloc)
//     : d_alloc_p(alloc)
//     {
//         assert(str);
//         assert(alloc);
//
//         std::size_t length = std::strlen(str);
//
//         d_str_p = static_cast<char *>(d_alloc_p->allocate(length + 1));
//         std::memcpy(d_str_p, str, length + 1);
//     }
//
//     /// Destroy this object.
//     ~String()
//     {
//         d_alloc_p->deallocate(d_str_p);
//     }
//
//     // ACCESSORS
//
//     /// Return a pointer providing modifiable access to the allocator
//     /// associated with this `String`.
//     bslma::Allocator *allocator() const
//     {
//         return d_alloc_p;
//     }
// };
// ```
// Next, we create a code fragment that will construct a managed `String`
// object using the default allocator to supply memory:
// ```
// void testInplaceCreation()
// {
// ```
// Suppose we want to have a different allocator supply memory allocated by the
// object:
// ```
//     bslma::TestAllocator ta;
//     bsls::Types::Int64   testBytesInUse = ta.numBytesInUse();
//
//     assert(0 == testBytesInUse);
//
//     bslma::TestAllocator         da;
//     bslma::DefaultAllocatorGuard dag(&da);
//     bsls::Types::Int64           defaultBytesInUse = da.numBytesInUse();
//
//     assert(0 == defaultBytesInUse);
// ```
// Then, create a string to copy:
// ```
//     const char *STR        = "Test string";
//     const int   STR_LENGTH = static_cast<int>(std::strlen(STR));
// ```
// Next, dynamically create an object and obtain the managed pointer referring
// to it using the `bslma::ManagedPtrUtil::makeManaged` function:
// ```
//     {
//         bslma::ManagedPtr<String> stringManagedPtr =
//                       bslma::ManagedPtrUtil::makeManaged<String>(STR, &ta);
// ```
// Note that memory for the object itself is supplied by the default allocator,
// while memory for the copy of the passed string is supplied by another
// allocator:
// ```
//         assert(static_cast<int>(sizeof(String)) <= da.numBytesInUse());
//         assert(&ta == stringManagedPtr->allocator());
//         assert(STR_LENGTH + 1 == ta.numBytesInUse());
//     }
// ```
// Then, make sure that all allocated memory is successfully released after
// managed pointer destruction:
// ```
//     assert(0 == da.numBytesInUse());
//     assert(0 == ta.numBytesInUse());
// ```
// If you want to use an allocator other than the default allocator, then the
// `allocateManaged` function should be used instead:
// ```
//     bslma::TestAllocator oa;
//     bsls::Types::Int64   objectBytesInUse = oa.numBytesInUse();
//     assert(0 == objectBytesInUse);
//
//     {
//         bslma::ManagedPtr<String> stringManagedPtr =
//              bslma::ManagedPtrUtil::allocateManaged<String>(&oa, STR, &ta);
//
//         assert(static_cast<int>(sizeof(String)) <= oa.numBytesInUse());
//         assert(&ta == stringManagedPtr->allocator());
//         assert(STR_LENGTH + 1 == ta.numBytesInUse());
//         assert(0 == da.numBytesInUse());
//     }
//
//     assert(0 == da.numBytesInUse());
//     assert(0 == ta.numBytesInUse());
//     assert(0 == oa.numBytesInUse());
// }
// ```
// Next, let's look at a more common scenario where the object's type uses
// `bslma` allocators.  In that case `allocateManaged` implicitly passes the
// supplied allocator to the object's constructor as an extra argument in the
// final position.
//
// The second example class almost completely repeats the first one, except
// that it explicitly defines the `bslma::UsesBslmaAllocator` trait:
// ```
// // Simple class that stores a copy of a null-terminated C-style string
// // and explicitly claims to use `bslma` allocators.
// class StringAlloc {
//
//   private:
//     // DATA
//     char             *d_str_p;    // stored value (owned)
//     bslma::Allocator *d_alloc_p;  // allocator to allocate any dynamic
//                                   // memory (held, not owned)
//
//   public:
//     // TRAITS
//     BSLMF_NESTED_TRAIT_DECLARATION(StringAlloc, bslma::UsesBslmaAllocator);
//
//     // CREATORS
//
//     /// Create an object having the same value as the specified `str`.
//     /// Optionally specify a `basicAllocator` used to supply memory.  If
//     /// `basicAllocator` is 0, the currently installed default allocator
//     /// is used.
//     StringAlloc(const char *str, bslma::Allocator *basicAllocator = 0)
//     : d_alloc_p(bslma::Default::allocator(basicAllocator))
//     {
//         assert(str);
//
//         std::size_t length = std::strlen(str);
//
//         d_str_p = static_cast<char *>(d_alloc_p->allocate(length + 1));
//         std::memcpy(d_str_p, str, length + 1);
//     }
//
//     /// Destroy this object.
//     ~StringAlloc()
//     {
//         d_alloc_p->deallocate(d_str_p);
//     }
//
//     // ACCESSORS
//
//     /// Return a pointer providing modifiable access to the allocator
//     /// associated with this `StringAlloc`.
//     bslma::Allocator *allocator() const
//     {
//         return d_alloc_p;
//     }
// };
// ```
// Then, let's create two managed objects using both `makeManaged` and
// `allocateManaged`:
// ```
// void testUsesAllocatorInplaceCreation()
// {
//     bslma::TestAllocator ta;
//     bsls::Types::Int64   testBytesInUse = ta.numBytesInUse();
//
//     assert(0 == testBytesInUse);
//
//     bslma::TestAllocator         da;
//     bslma::DefaultAllocatorGuard dag(&da);
//     bsls::Types::Int64           defaultBytesInUse = da.numBytesInUse();
//
//     assert(0 == defaultBytesInUse);
//
//     const char *STR        = "Test string";
//     const int   STR_LENGTH = static_cast<int>(std::strlen(STR));
//
// ```
// Note that we need to explicitly supply the allocator's address to
// `makeManaged` to be passed to the object's constructor:
// ```
//     {
//         bslma::ManagedPtr<StringAlloc> stringManagedPtr =
//                  bslma::ManagedPtrUtil::makeManaged<StringAlloc>(STR, &ta);
//
//         assert(static_cast<int>(sizeof(String)) <= da.numBytesInUse());
//         assert(&ta == stringManagedPtr->allocator());
//         assert(STR_LENGTH + 1 == ta.numBytesInUse());
//     }
//
// ```
// But the supplied allocator is implicitly passed to the constructor by
// `allocateManaged`:
// ```
//     {
//         bslma::ManagedPtr<StringAlloc> stringManagedPtr =
//              bslma::ManagedPtrUtil::allocateManaged<StringAlloc>(&ta, STR);
//
//         assert(static_cast<int>(sizeof(String)) + STR_LENGTH + 1 <=
//                                                        ta.numBytesInUse());
//         assert(&ta == stringManagedPtr->allocator());
//         assert(0 == da.numBytesInUse());
//     }
// ```
// Finally, make sure that all allocated memory is successfully released after
// the managed pointers (and the objects they manage) are destroyed:
// ```
//     assert(0 == da.numBytesInUse());
//     assert(0 == ta.numBytesInUse());
// }
// ```

#include <bslscm_version.h>

#include <bslma_allocator.h>
#include <bslma_constructionutil.h>
#include <bslma_deallocateobjectproctor.h>
#include <bslma_default.h>
#include <bslma_managedptr_factorydeleter.h>
#include <bslma_managedptr_members.h>
#include <bslma_managedptr_pairproxy.h>
#include <bslma_managedptrdeleter.h>

#include <bslmf_addreference.h>
#include <bslmf_assert.h>
#include <bslmf_conditional.h>
#include <bslmf_enableif.h>
#include <bslmf_haspointersemantics.h>
#include <bslmf_isbitwisemoveable.h>
#include <bslmf_isclass.h>
#include <bslmf_isconvertible.h>
#include <bslmf_isnothrowmoveconstructible.h>
#include <bslmf_isvoid.h>
#include <bslmf_movableref.h>
#include <bslmf_removecv.h>
#include <bslmf_util.h>    // 'forward(V)'

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_nullptr.h>
#include <bsls_platform.h>
#include <bsls_unspecifiedbool.h>
#include <bsls_util.h>     // 'forward<T>(V)'

#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
// clang-format off
// Include version that can be compiled with C++03
// Generated on Mon Jan 13 08:31:27 2025
// Command line: sim_cpp11_features.pl bslma_managedptr.h

# define COMPILING_BSLMA_MANAGEDPTR_H
# include <bslma_managedptr_cpp03.h>
# undef COMPILING_BSLMA_MANAGEDPTR_H

// clang-format on
#else

namespace BloombergLP {
namespace bslma {

                  // =================================
                  // private struct ManagedPtr_ImpUtil
                  // =================================

/// This `struct` provides a namespace for utility functions used to obtain
/// the necessary types of pointers.
struct ManagedPtr_ImpUtil {

    // CLASS METHODS

    /// Return the specified `address` cast as a pointer to `void`, even if
    /// (the template parameter) `TYPE` is cv-qualified.
    template <class TYPE>
    static void *voidify(TYPE *address) BSLS_KEYWORD_NOEXCEPT;

    /// Return the specified `address` of a potentially cv-qualified object
    /// of the given (template parameter) `TYPE`, cast as a pointer to
    /// non-cv-qualified `TYPE`.
    template <class TYPE>
    static TYPE *unqualify(const volatile TYPE *address) BSLS_KEYWORD_NOEXCEPT;
};
                    // ============================
                    // private class ManagedPtr_Ref
                    // ============================

/// This class holds a managed pointer reference, returned by the implicit
/// conversion operator in the class `ManagedPtr`.  This class is used to
/// allow the construction of managed pointers from temporary managed
/// pointer objects, since temporaries cannot bind to the reference to a
/// modifiable object used in the copy constructor and copy-assignment
/// operator for `ManagedPtr`.  Note that while no members or methods of
/// this class template depend on the specified `TARGET_TYPE`, it is
/// important to carry this type into conversions to support passing
/// ownership of `ManagedPtr_Members` pointers when assigning or
/// constructing `ManagedPtr` objects.
template <class TARGET_TYPE>
class ManagedPtr_Ref {

    // DATA
    ManagedPtr_Members *d_base_p;  // non-null pointer to the managed state of
                                   // a 'ManagedPtr' object

    TARGET_TYPE        *d_cast_p;  // safely-cast pointer to the referenced
                                   // object

  public:
    // CREATORS

    /// Create a `ManagedPtr_Ref` object having the specified `base` value
    /// for its `base` attribute, and the specified `target` for its
    /// `target` attribute.  Note that `target` (but not `base`) may be
    /// null.
    ManagedPtr_Ref(ManagedPtr_Members *base, TARGET_TYPE *target);

    //! ManagedPtr_Ref(const ManagedPtr_Ref& original) = default;
        // Create a 'ManagedPtr_Ref' object having the same 'd_base_p' value as
        // the specified 'original'.  Note that this trivial constructor's
        // definition is compiler generated.

    /// Destroy this object.  Note that the referenced managed object is
    /// *not* destroyed.
    ~ManagedPtr_Ref();

    // MANIPULATORS
    //! ManagedPtr_Ref& operator=(const ManagedPtr_Ref& original) = default;
        // Create a 'ManagedPtr_Ref' object having the same 'd_base_p' as the
        // specified 'original'.  Note that this trivial copy-assignment
        // operator's definition is compiler generated.

    // ACCESSORS

    /// Return a pointer to the managed state of a `ManagedPtr` object.
    ManagedPtr_Members *base() const;

    /// Return a pointer to the referenced object.
    TARGET_TYPE *target() const;
};

                    // =========================================
                    // private struct ManagedPtr_TraitConstraint
                    // =========================================

/// This `struct` is an empty type that exists solely to enable constructor
/// access to be constrained by type trait.
struct ManagedPtr_TraitConstraint {
};
                           // ================
                           // class ManagedPtr
                           // ================

/// This class is a "smart pointer" that refers to a *target* object
/// accessed via a pointer to the specified parameter type, `TARGET_TYPE`,
/// and that supports sole ownership of a *managed* object that is
/// potentially of a different type, and may be an entirely different object
/// from the target object.  A managed pointer ensures that the object it
/// manages is destroyed when the managed pointer is destroyed (or
/// re-assigned), using the "deleter" supplied along with the managed
/// object.  The target object referenced by a managed pointer may be
/// accessed using either the `->` operator, or the dereference operator
/// (`operator *`).  The specified `TARGET_TYPE` may be `const`-qualified,
/// but may not be `volatile`-qualified, nor may it be a reference type.
///
/// A managed pointer may be *empty*, in which case it neither refers to a
/// target object nor owns a managed object.  An empty managed pointer is
/// the equivalent of a null pointer: Such a managed pointer is not
/// de-referenceable, and tests as `false` in boolean expressions.
///
/// A managed pointer for which the managed object is not the same object as
/// the target is said to *alias* the managed object (see the section
/// "Aliasing" in the component-level documentation).
template <class TARGET_TYPE>
class ManagedPtr {

  public:
    // INTERFACE TYPES

    /// Alias for a function-pointer type for functions used to destroy the
    /// object managed by a `ManagedPtr` object.
    typedef ManagedPtrDeleter::Deleter DeleterFunc;

    /// Alias to the `TARGET_TYPE` template parameter.
    typedef TARGET_TYPE element_type;

  private:
    // PRIVATE TYPES

    /// `BoolType` is an alias for an unspecified type that is implicitly
    /// convertible to `bool`, but will not promote to `int`.  This (opaque)
    /// type can be used as an "unspecified boolean type" for converting a
    /// managed pointer to `bool` in contexts such as `if (mp) { ... }`
    /// without actually having a conversion to `bool` or being less-than
    /// comparable (either of which would also enable undesirable implicit
    /// comparisons of managed pointers to `int` and less-than comparisons).
    typedef typename bsls::UnspecifiedBool<ManagedPtr>::BoolType BoolType;

    /// This `typedef` is a convenient alias for the utility associated with
    /// movable references.
    typedef bslmf::MovableRefUtil                                MoveUtil;

    // DATA
    ManagedPtr_Members d_members;  // state managed by this object

    // PRIVATE CLASS METHODS

    /// Return the value of the specified `ptr` as a `void *`, after
    /// stripping all `const` and `volatile` qualifiers from `TARGET_TYPE`.
    /// This function avoids accidental type-safety errors when performing
    /// the necessary sequence of casts.  Note that calling this function
    /// implies a conversion of the calling pointer to `TARGET_TYPE *`,
    /// which, in rare cases, may involve some adjustment of the pointer
    /// value, e.g., in the case of multiple inheritance where `TARGET_TYPE`
    /// is not a left-most base of the complete object type.
    static void *stripBasePointerType(TARGET_TYPE *ptr);

    /// Return the value of the specified `ptr` as a `void *`, after
    /// stripping all `const` and `volatile` qualifiers from `MANAGED_TYPE`.
    /// This function avoids accidental type-safety errors when performing
    /// the necessary sequence of casts.
    template <class MANAGED_TYPE>
    static void *stripCompletePointerType(MANAGED_TYPE *ptr);

    // PRIVATE MANIPULATORS

    /// Destroy the currently managed object, if any.  Then, set the target
    /// object of this managed pointer to be that referenced by the
    /// specified `ptr`, take ownership of `*ptr` as the currently managed
    /// object, and set a deleter that will invoke the specified `deleter`
    /// with the address of the currently managed object, and with the
    /// specified `cookie` (that the deleter can use for its own purposes),
    /// unless `0 == ptr`, in which case reset this managed pointer to
    /// empty.  The behavior is undefined if `ptr` is already managed by
    /// another object, or if `0 == deleter && 0 != ptr`.
    template <class MANAGED_TYPE>
    void loadImp(MANAGED_TYPE *ptr, void *cookie, DeleterFunc deleter);

  private:
    // NOT IMPLEMENTED

    /// It is never defined behavior to pass a null pointer literal as a
    /// factory, unless the specified `ptr` is also a null pointer literal.
    template <class MANAGED_TYPE>
    ManagedPtr(MANAGED_TYPE *, bsl::nullptr_t);

  private:
    // NOT IMPLEMENTED

    /// It is never defined behavior to pass a null literal as a deleter,
    /// unless the `object` pointer is also a null pointer literal.
    template <class MANAGED_TYPE, class COOKIE_TYPE>
    ManagedPtr(MANAGED_TYPE *, COOKIE_TYPE *, bsl::nullptr_t);

  private:
    // NOT IMPLEMENTED

    /// It is never defined behavior to pass a null literal as a deleter,
    /// unless the `object` pointer is also a null pointer literal.
    template <class MANAGED_TYPE>
    void load(MANAGED_TYPE *, bsl::nullptr_t, bsl::nullptr_t);
    template <class COOKIE_TYPE>
    void load(TARGET_TYPE *, COOKIE_TYPE *, bsl::nullptr_t);

  private:
    // NOT IMPLEMENTED

    /// These two operator overloads are declared as `private` but never
    /// defined in order to eliminate accidental equality comparisons that
    /// would occur through the implicit conversion to `BoolType`.  Note
    /// that the return type of `void` is chosen as it will often produce a
    /// clearer error message than relying on the `private` control failure.
    /// Also note that these private operators will not be needed with
    /// C++11, where an `explicit operator bool()` conversion operator would
    /// be preferred.
    void operator==(const ManagedPtr&) const;
    void operator!=(const ManagedPtr&) const;

    // FRIENDS
    template <class ALIASED_TYPE>
    friend class ManagedPtr;  // required only for alias support

  public:
    // CREATORS

    /// Create an empty managed pointer.
    ManagedPtr();
    ManagedPtr(bsl::nullptr_t);  // IMPLICIT

    /// Create a managed pointer having a target object referenced by the
    /// specified `ptr`, owning the managed object `*ptr`, and having a
    /// deleter that will call `delete ptr` to destroy the managed object
    /// when invoked (e.g., when this managed pointer object is destroyed),
    /// unless `0 == ptr`, in which case create an empty managed pointer.
    /// The deleter will invoke the destructor of `MANAGED_TYPE` rather than
    /// the destructor of `TARGET_TYPE`.  This constructor will not compile
    /// unless `MANAGED_TYPE *` is convertible to `TARGET_TYPE *`.  Note
    /// that this behavior allows `ManagedPtr` to be defined for `void`
    /// pointers, and to call the correct destructor for the managed object,
    /// even if the destructor for `TARGET_TYPE` is not declared as
    /// `virtual`.  The behavior is undefined unless the managed object (if
    /// any) can be destroyed by `delete`, or if the lifetime of the managed
    /// object is already managed by another object.
    template <class MANAGED_TYPE>
    explicit ManagedPtr(MANAGED_TYPE *ptr);

    /// Create a managed pointer having the same target object as the
    /// managed pointer referenced by the specified `ref`, transfer
    /// ownership of the managed object owned by the managed pointer
    /// referenced by `ref`, and reset the managed pointer referenced by
    /// `ref` to empty.  This constructor is used to create a managed
    /// pointer from a managed pointer rvalue, or from a managed pointer to
    /// a "compatible" type, where "compatible" means a built-in conversion
    /// from `COMPATIBLE_TYPE *` to `TARGET_TYPE *` is defined, e.g.,
    /// `derived *` to `base *`, `T *` to `const T *`, or `T *` to `void *`.
    ManagedPtr(ManagedPtr_Ref<TARGET_TYPE> ref)
                                             BSLS_KEYWORD_NOEXCEPT; // IMPLICIT

    ManagedPtr(ManagedPtr& original)                   BSLS_KEYWORD_NOEXCEPT;

    /// Create a managed pointer having the same target object as the
    /// specified `original`, transfer ownership of the object managed by
    /// `original` (if any) to this managed pointer, and reset `original` to
    /// empty.
    ManagedPtr(bslmf::MovableRef<ManagedPtr> original) BSLS_KEYWORD_NOEXCEPT;

    /// Create a managed pointer having the same target object as the specified
    /// `original`, transfer ownership of the object managed by `original` (if
    /// any) to this managed pointer, and reset `original` to empty.
    /// `TARGET_TYPE` must be an accessible and unambiguous base of
    /// `BDE_OTHER_TYPE`
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    template <class BDE_OTHER_TYPE>
    ManagedPtr(ManagedPtr<BDE_OTHER_TYPE>&& original,
               typename bsl::enable_if<
                   bsl::is_convertible<BDE_OTHER_TYPE *, TARGET_TYPE *>::value,
                   ManagedPtr_TraitConstraint>::type =
                       ManagedPtr_TraitConstraint())
        BSLS_KEYWORD_NOEXCEPT;
#elif defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
    // sun compiler version 12.3 and earlier
    template <class BDE_OTHER_TYPE>
    ManagedPtr(bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > original)
        BSLS_KEYWORD_NOEXCEPT;
#else // c++03 except old (version <= 12.3) sun compilers
    template <class BDE_OTHER_TYPE>
    ManagedPtr(bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > original,
               typename bsl::enable_if<
                 bsl::is_convertible<BDE_OTHER_TYPE *, TARGET_TYPE *>::value,
                 ManagedPtr_TraitConstraint>::type =
                     ManagedPtr_TraitConstraint())
        BSLS_KEYWORD_NOEXCEPT;
#endif

    /// Create a managed pointer that takes ownership of the object managed
    /// by the specified `alias`, but which uses the specified `ptr` to
    /// refer to its target object, unless `0 == ptr`, in which case create
    /// an empty managed pointer.  Reset `alias` to empty if ownership of
    /// its managed object is transferred.  The behavior is undefined if
    /// `alias` is empty, but `0 != ptr`.  Note that destroying or
    /// re-assigning a managed pointer created with this constructor will
    /// destroy the object originally managed by `alias` (unless `release`
    /// is called first); the destructor for `*ptr` is not called directly.
    template <class ALIASED_TYPE>
    ManagedPtr(ManagedPtr<ALIASED_TYPE>& alias, TARGET_TYPE *ptr);
    template <class ALIASED_TYPE>
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    ManagedPtr(ManagedPtr<ALIASED_TYPE>&&                    alias,
#else
    ManagedPtr(bslmf::MovableRef<ManagedPtr<ALIASED_TYPE> >  alias,
#endif
               TARGET_TYPE                                  *ptr);

    /// Create a managed pointer having a target object referenced by the
    /// specified `ptr`, owning the managed object `*ptr`, and having a
    /// deleter that will call `factory->deleteObject(ptr)` to destroy the
    /// managed object when invoked (e.g., when this managed pointer object
    /// is destroyed), unless `0 == ptr`, in which case create an empty
    /// managed pointer.  The deleter will invoke the destructor of
    /// `MANAGED_TYPE` rather than the destructor of `TARGET_TYPE`.  This
    /// constructor will not compile unless `MANAGED_TYPE *` is convertible
    /// to `TARGET_TYPE *`.  The behavior is undefined unless the managed
    /// object (if any) can be destroyed by the specified `factory`, or if
    /// `0 == factory && 0 != ptr`, or if the lifetime of the managed object
    /// is already managed by another object.  Note that `bslma::Allocator`,
    /// and any class publicly and unambiguously derived from
    /// `bslma::Allocator`, meets the requirements for `FACTORY_TYPE`.
    template <class MANAGED_TYPE, class FACTORY_TYPE>
    ManagedPtr(MANAGED_TYPE *ptr, FACTORY_TYPE *factory);

    /// Create an empty managed pointer.  Note that this constructor is
    /// necessary to match null-pointer literal arguments, in order to break
    /// ambiguities and provide valid type deduction with the other
    /// constructor templates in this class.
    explicit ManagedPtr(bsl::nullptr_t, bsl::nullptr_t);

    /// Create an empty managed pointer.  Note that the specified `factory`
    /// is ignored, as an empty managed pointer does not call its deleter.
    template <class FACTORY_TYPE>
    ManagedPtr(bsl::nullptr_t, FACTORY_TYPE *factory);

    /// Create a managed pointer having a target object referenced by the
    /// specified `ptr`, owning the managed object `*ptr`, and having a
    /// deleter that will invoke the specified `deleter` with the address of
    /// the currently managed object, and with the specified `cookie` (that
    /// the deleter can use for its own purposes), unless `0 == ptr`, in
    /// which case create an empty managed pointer.  The behavior is
    /// undefined if `ptr` is already managed by another object, or if
    /// `0 == deleter && 0 != ptr`.  Note that this constructor is required
    /// only because the deprecated overloads cause an ambiguity in its
    /// absence; it should be removed when the deprecated overloads are
    /// removed.
    ManagedPtr(TARGET_TYPE *ptr, void *cookie, DeleterFunc deleter);

    /// Create a managed pointer having a target object referenced by the
    /// specified `ptr`, owning the managed object `*ptr`, and having a
    /// deleter that will invoke the specified `deleter` with the address of
    /// the currently managed object, and with the specified `cookie` (that
    /// the deleter can use for its own purposes), unless `0 == ptr`, in
    /// which case create an empty managed pointer.  This constructor will
    /// not compile unless `MANAGED_TYPE *` is convertible to
    /// `TARGET_TYPE *`.  The deleter will invoke the destructor of
    /// `MANAGED_TYPE` rather than the destructor of `TARGET_TYPE`.  The
    /// behavior is undefined if `ptr` is already managed by another object,
    /// or if `0 == deleter && 0 != ptr`.
    template <class MANAGED_TYPE>
    ManagedPtr(MANAGED_TYPE *ptr, void *cookie, DeleterFunc deleter);

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    /// Create a managed pointer having a target object referenced by the
    /// specified `ptr`, owning the managed object `*ptr`, and having a
    /// deleter that will invoke the specified `deleter` with the address of
    /// the currently managed object, and with the specified `cookie` (that
    /// the deleter can use for its own purposes), unless `0 == ptr`, in
    /// which case create an empty managed pointer.  This constructor will
    /// not compile unless `MANAGED_TYPE *` is convertible to
    /// `TARGET_TYPE *`, and `MANAGED_TYPE *` is convertible to
    /// `MANAGED_BASE *`.  The deleter will invoke the destructor of
    /// `MANAGED_TYPE` rather than the destructor of `TARGET_TYPE`.  The
    /// behavior is undefined if `ptr` is already managed by another object,
    /// or if `0 == deleter && 0 != ptr`.  Note that this constructor is
    /// needed only to avoid ambiguous type deductions when passing a null
    /// pointer literal as the `cookie` when the user passes a deleter
    /// taking a type other than `void *` for its object type.  Also note
    /// that this function is *deprecated* as it relies on undefined
    /// compiler behavior for its implementation (that luckily performs as
    /// required on every platform supported by BDE).
    ///
    /// @DEPRECATED: Instead, use:
    /// ```
    /// template <class MANAGED_TYPE>
    /// ManagedPtr(MANAGED_TYPE *ptr, void *cookie, DeleterFunc deleter);
    /// ```
    template <class MANAGED_TYPE, class MANAGED_BASE>
    ManagedPtr(MANAGED_TYPE *ptr,
               void         *cookie,
               void        (*deleter)(MANAGED_BASE *, void *));

    /// Create a managed pointer having a target object referenced by the
    /// specified `ptr`, owning the managed object `*ptr`, and having a
    /// deleter that will invoke the specified `deleter` with the address of
    /// the currently managed object, and with the specified `cookie` (that
    /// the deleter can use for its own purposes), unless `0 == ptr`, in
    /// which case create an empty managed pointer.  This constructor will
    /// not compile unless `MANAGED_TYPE *` is convertible to
    /// `TARGET_TYPE *`, and `MANAGED_TYPE *` is convertible to
    /// `MANAGED_BASE *`.  The deleter will invoke the destructor of
    /// `MANAGED_TYPE` rather than the destructor of `TARGET_TYPE`.  The
    /// behavior is undefined if `ptr` is already managed by another object,
    /// or if `0 == deleter && 0 != ptr`.  Note that this function is
    /// *deprecated* as it relies on undefined compiler behavior for its
    /// implementation (that luckily performs as required on every platform
    /// supported by BDE).
    ///
    /// @DEPRECATED: Instead, use:
    /// ```
    /// template <class MANAGED_TYPE>
    /// ManagedPtr(MANAGED_TYPE *ptr, void *cookie, DeleterFunc deleter);
    /// ```
    template <class MANAGED_TYPE,
              class MANAGED_BASE,
              class COOKIE_TYPE,
              class COOKIE_BASE>
    ManagedPtr(MANAGED_TYPE *ptr,
               COOKIE_TYPE  *cookie,
               void        (*deleter)(MANAGED_BASE *, COOKIE_BASE *));
#endif // BDE_OMIT_INTERNAL_DEPRECATED

    /// Destroy this managed pointer object.  Destroy the object managed by
    /// this managed pointer by invoking the user-supplied deleter, unless
    /// this managed pointer is empty, in which case the deleter will *not*
    /// be called.
    ~ManagedPtr();

    // MANIPULATORS
    ManagedPtr& operator=(ManagedPtr& rhs)               BSLS_KEYWORD_NOEXCEPT;

    /// If this object and the specified `rhs` manage the same object,
    /// return a reference to this managed pointer; otherwise, destroy the
    /// managed object owned by this managed pointer, transfer ownership of
    /// the managed object owned by `rhs` to this managed pointer, set this
    /// managed pointer to point to the target object referenced by `rhs`,
    /// reset `rhs` to empty, and return a reference to this managed
    /// pointer.
    ManagedPtr& operator=(bslmf::MovableRef<ManagedPtr> rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

    /// If this object and the specified `rhs` manage the same object,
    /// return a reference to this managed pointer; otherwise, destroy the
    /// managed object owned by this managed pointer, transfer ownership of
    /// the managed object owned by `rhs` to this managed pointer, set this
    /// managed pointer to point to the target object referenced by `rhs`,
    /// reset `rhs` to empty, and return a reference to this managed
    /// pointer.  `TARGET_TYPE` must be an accessible and unambiguous base
    /// of `BDE_OTHER_TYPE`
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    template <class BDE_OTHER_TYPE>
    typename bsl::enable_if<
        bsl::is_convertible<BDE_OTHER_TYPE *, TARGET_TYPE *>::value,
        ManagedPtr<TARGET_TYPE> >::type&
    operator=(ManagedPtr<BDE_OTHER_TYPE>&& rhs) BSLS_KEYWORD_NOEXCEPT;
#elif defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
    // sun compiler version 12.3 and earlier
    template <class BDE_OTHER_TYPE>
    ManagedPtr<TARGET_TYPE>&
    operator=(bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > rhs)
        BSLS_KEYWORD_NOEXCEPT;
#else // c++03 except old (version <= 12.3) sun compilers
    template <class BDE_OTHER_TYPE>
    typename bsl::enable_if<
        bsl::is_convertible<BDE_OTHER_TYPE *, TARGET_TYPE *>::value,
        ManagedPtr<TARGET_TYPE> >::type&
    operator=(bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > rhs)
        BSLS_KEYWORD_NOEXCEPT;
#endif

    /// If this object and the managed pointer reference by the specified
    /// `ref` manage the same object, return a reference to this managed
    /// pointer; otherwise, destroy the managed object owned by this managed
    /// pointer, transfer ownership of the managed object owned by the
    /// managed pointer referenced by `ref`, and set this managed pointer to
    /// point to the target object currently referenced the managed pointer
    /// referenced by `ref`; then reset the managed pointer referenced by
    /// `ref` to empty, and return a reference to this managed pointer.
    /// This operator is (implicitly) used to assign from a managed pointer
    /// rvalue, or from a managed pointer to a "compatible" type, where
    /// "compatible" means a built-in conversion from `MANAGED_TYPE *` to
    /// `TARGET_TYPE *` is defined, e.g., `derived *` to `base *`, `T *` to
    /// `const T *`, or `T *` to `void *`.
    ManagedPtr& operator=(ManagedPtr_Ref<TARGET_TYPE> ref)
                                                         BSLS_KEYWORD_NOEXCEPT;

    /// Destroy the current managed object (if any) and reset this managed
    /// pointer to empty.
    ManagedPtr& operator=(bsl::nullptr_t);

    /// Return a managed pointer reference, referring to this object.  Note
    /// that this conversion operator is used implicitly to allow the
    /// construction of managed pointers from rvalues because temporaries
    /// cannot be passed by references offering modifiable access.
    template <class REFERENCED_TYPE>
    operator ManagedPtr_Ref<REFERENCED_TYPE>();

    /// Destroy the current managed object (if any) and reset this managed
    /// pointer to empty.
    ///
    /// @DEPRECATED: Use `reset` instead.
    void clear();

    /// Destroy the currently managed object, if any.  Then, set the target
    /// object of this managed pointer to be that referenced by the
    /// specified `ptr`, take ownership of `*ptr` as the currently managed
    /// object, and set a deleter that uses the currently installed default
    /// allocator to destroy the managed object when invoked (e.g., when
    /// this managed pointer object is destroyed), unless `0 == ptr`, in
    /// which case reset this managed pointer to empty.  The deleter will
    /// invoke the destructor of `MANAGED_TYPE` rather than the destructor
    /// of `TARGET_TYPE`.  This function will not compile unless
    /// `MANAGED_TYPE *` is convertible to `TARGET_TYPE *`.  The behavior is
    /// undefined unless the managed object (if any) can be destroyed by the
    /// currently installed default allocator, or if the lifetime of the
    /// managed object is already managed by another object.
    template <class MANAGED_TYPE>
    void load(MANAGED_TYPE *ptr);

    /// Destroy the currently managed object, if any.  Then, set the target
    /// object of this managed pointer to be that referenced by the
    /// specified `ptr`, take ownership of `*ptr` as the currently managed
    /// object, and set a deleter that calls `factory->deleteObject(ptr)` to
    /// destroy the managed object when invoked (e.g., when this managed
    /// pointer object is destroyed), unless `0 == ptr`, in which case reset
    /// this managed pointer to empty.  The deleter will invoke the
    /// destructor of `MANAGED_TYPE` rather than the destructor of
    /// `TARGET_TYPE`.  This function will not compile unless
    /// `MANAGED_TYPE *` is convertible to `TARGET_TYPE *`.  The behavior is
    /// undefined unless the managed object (if any) can be destroyed by the
    /// specified `factory`,  or if `0 == factory && 0 != ptr`, or if the
    /// the lifetime of the managed object is already managed by another
    /// object.  Note that `bslma::Allocator`, and any class publicly and
    /// unambiguously derived from `bslma::Allocator`, meets the
    /// requirements for `FACTORY_TYPE`.
    template <class MANAGED_TYPE, class FACTORY_TYPE>
    void load(MANAGED_TYPE *ptr, FACTORY_TYPE *factory);

    /// Destroy the currently managed object, if any.  Then, set the target
    /// object of this managed pointer to be that referenced by the
    /// specified `ptr`, take ownership of `*ptr` as the currently managed
    /// object, and set a deleter that will invoke the specified `deleter`
    /// with the address of the currently managed object, and with the
    /// specified `cookie` (that the deleter can use for its own purposes),
    /// unless `0 == ptr`, in which case reset this managed pointer to
    /// empty.  The behavior is undefined if `ptr` is already managed by
    /// another object, or if `0 == deleter && 0 != ptr`.  Note that GCC 3.4
    /// and earlier versions have a bug in template type deduction/overload
    /// resolution that causes ambiguities if this signature is available.
    /// This function will be restored on that platform once the deprecated
    /// signatures are finally removed.
    template <class MANAGED_TYPE>
    void load(MANAGED_TYPE *ptr, void *cookie, DeleterFunc deleter);

    /// Destroy the current managed object (if any) and reset this managed
    /// pointer to empty.  Note that the optionally specified `cookie` and
    /// `deleter` will be ignored, as empty managed pointers do not invoke a
    /// deleter.
    void load(bsl::nullptr_t = 0, void *cookie = 0, DeleterFunc deleter = 0);

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    template <class MANAGED_TYPE, class COOKIE_TYPE>
    void load(MANAGED_TYPE *ptr, COOKIE_TYPE *cookie, DeleterFunc deleter);

    template <class MANAGED_TYPE, class MANAGED_BASE>
    void load(MANAGED_TYPE *ptr,
              void         *cookie,
              void        (*deleter)(MANAGED_BASE *, void *));

    /// Destroy the currently managed object, if any.  Then, set the target
    /// object of this managed pointer to be that referenced by the
    /// specified `ptr`, take ownership of `*ptr` as the currently managed
    /// object, and set a deleter that will invoke the specified `deleter`
    /// with the address of the currently managed object, and with the
    /// specified `cookie` (that the deleter can use for its own purposes),
    /// unless `0 == ptr`, in which case reset this managed pointer to
    /// empty.  The behavior is undefined if `ptr` is already managed by
    /// another object, or if `0 == deleter && 0 != ptr`.  Note that this
    /// function is *deprecated* as it relies on undefined compiler behavior
    /// for its implementation, but luckily perform as required for all
    /// currently supported platforms; on platforms where the non-deprecated
    /// overload is not available (e.g., GCC 3.4) code should be written as
    /// if it were available, as an appropriate (deprecated) overload will
    /// be selected with the correct (non-deprecated) behavior.
    ///
    /// @DEPRECATED: Instead, use:
    /// ```
    /// template <class MANAGED_TYPE>
    /// void load(MANAGED_TYPE *ptr, void *cookie, DeleterFunc deleter);
    /// ```
    template <class MANAGED_TYPE,
              class MANAGED_BASE,
              class COOKIE_TYPE,
              class COOKIE_BASE>
    void load(MANAGED_TYPE *ptr,
              COOKIE_TYPE  *cookie,
              void        (*deleter)(MANAGED_BASE *, COOKIE_BASE *));
#endif // BDE_OMIT_INTERNAL_DEPRECATED

    /// If the specified `alias` manages the same object as this managed
    /// pointer, set the target object of this managed pointer to be that
    /// referenced by the specified `ptr`; otherwise, destroy the currently
    /// managed object (if any), and if `alias` is empty, reset this managed
    /// pointer to empty; otherwise, transfer ownership (and the deleter) of
    /// the object managed by `alias`, and set the target object of this
    /// managed pointer to be that referenced by `ptr`.  The behavior is
    /// undefined if `0 == ptr` and `alias` is not empty, or if `0 != ptr`
    /// and `alias` is empty, or if `ptr` is already managed by a managed
    /// pointer other than `alias`.  Note that this establishes a managed
    /// pointer where `ptr` aliases `alias`.  The managed object for `alias`
    /// will ultimately be destroyed, and the destructor for `ptr` is not
    /// called directly.
    template <class ALIASED_TYPE>
    void loadAlias(ManagedPtr<ALIASED_TYPE>& alias, TARGET_TYPE *ptr);

    /// Return a raw pointer to the current target object (if any) and the
    /// deleter for the currently managed object, and reset this managed
    /// pointer to empty.  It is undefined behavior to run the returned
    /// deleter unless the returned pointer to target object is not null.
    ManagedPtr_PairProxy<TARGET_TYPE, ManagedPtrDeleter> release();

    /// Load the specified `deleter` for the currently managed object and
    /// reset this managed pointer to empty.  Return a raw pointer to the
    /// target object (if any) managed by this pointer.  It is undefined
    /// behavior to run the returned deleter unless the returned pointer to
    /// target object is not null.
    TARGET_TYPE *release(ManagedPtrDeleter *deleter);

    /// Destroy the current managed object (if any) and reset this managed
    /// pointer to empty.
    void reset();

    /// Exchange the value and ownership of this managed pointer with the
    /// specified `other` managed pointer.
    void swap(ManagedPtr& other);

    // ACCESSORS

    /// Return `true` if this managed pointer is empty, and `false` otherwise.
    bool operator==(bsl::nullptr_t) const;

    /// Return `false` if this managed pointer is empty, and `true` otherwise.
    bool operator!=(bsl::nullptr_t) const;

    /// Return a value of "unspecified bool" type that evaluates to `false`
    /// if this managed pointer is empty, and `true` otherwise.  Note that
    /// this conversion operator allows a managed pointer to be used within
    /// a conditional context, such as within an `if` or `while` statement,
    /// but does *not* allow managed pointers to be compared (e.g., via `<`
    /// or `>`).  Also note that a superior solution is available in C++11
    /// using the `explicit operator bool()` syntax, that removes the need
    /// for a special boolean-like type and private equality-comparison
    /// operators.
    operator BoolType() const;

    /// Return a reference to the target object.  The behavior is undefined
    /// if this managed pointer is empty, or if `TARGET_TYPE` is `void` or
    /// `const void`.
    typename bslmf::AddReference<TARGET_TYPE>::Type operator*() const;

    /// Return the address of the target object, or 0 if this managed
    /// pointer is empty.
    TARGET_TYPE *operator->() const;

    /// Return a reference to the non-modifiable deleter information
    /// associated with this managed pointer.  The behavior is undefined if
    /// this managed pointer is empty.
    const ManagedPtrDeleter& deleter() const;

    /// Return the address of the target object, or 0 if this managed
    /// pointer is empty.
    TARGET_TYPE *get() const;

    /// Return the address of the target object, or 0 if this managed
    /// pointer is empty.
    ///
    /// @DEPRECATED: Use `get` instead.
    TARGET_TYPE *ptr() const;
};

// FREE FUNCTIONS

/// Efficiently exchange the values of the specified `a` and `b` objects.
/// This function provides the no-throw exception-safety guarantee.
template <class TARGET_TYPE>
void swap(ManagedPtr<TARGET_TYPE>& a, ManagedPtr<TARGET_TYPE>& b);

                        // =====================
                        // struct ManagedPtrUtil
                        // =====================

/// This utility class provides a general no-op deleter, which is useful
/// when creating managed pointers to stack-allocated objects.
struct ManagedPtrUtil {

    // CLASS METHODS

    /// Deleter function that does nothing.
    static void noOpDeleter(void *, void *);

    /// Make use of `AllocatorUtil::deleteObject` to destroy and deallocate
    /// the specified `object` using the specified allocator.  The behavior is
    /// undefined unless `allocator` is an instance of `bslma::Allocator`
    /// that was used to supply memory for `object` and `object` points to an
    /// instance of `ELEMENT_TYPE` that is within its lifetime.
    template <class ELEMENT_TYPE>
    static void allocatorDeleter(void *object, void *allocator);

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14

    /// Create an object of the (template parameter) `ELEMENT_TYPE` from the
    /// specified `args...` arguments, and return a `ManagedPtr` to manage
    /// the new object.  Use the specified `allocator` to supply memory for
    /// the footprint of the new object and implicitly pass `allocator` as
    /// the allocator argument to the `ELEMENT_TYPE` constructor if
    /// `bslma::UsesBslmaAllocator<ELEMENT_TYPE>::value` is `true`.  If
    /// `allocator` is a null pointer, the currently installed default
    /// allocator is used.  Note that compilation will fail unless
    /// `allocator` is convertible to either `bslma::Allocator *` or
    /// `bsl::allocator<>`.
    template <class ELEMENT_TYPE, class... ARGS>
    static ManagedPtr<ELEMENT_TYPE>
    allocateManaged(bslma::Allocator *allocator, ARGS&&...   args);
    template <class ELEMENT_TYPE, class ALLOCATOR, class... ARGS>
    static typename bsl::enable_if<bsl::is_class<ALLOCATOR>::value,
                                   ManagedPtr<ELEMENT_TYPE> >::type
    allocateManaged(const ALLOCATOR& allocator, ARGS&&... args);

    /// Create an object of the (template parameter) `ELEMENT_TYPE` from the
    /// specified `args...` arguments, and return a `ManagedPtr` to manage
    /// the new object.  Use the currently installed default allocator to
    /// supply memory for the footprint of the new object but do *not*
    /// implicitly pass the default allocator as the allocator argument to
    /// its constructor even if
    /// `bslma::UsesBslmaAllocator<ELEMENT_TYPE>::value` is `true`.  Note
    /// that an allocator may be included in `args`, but see
    /// `allocateManaged` for an alternative function that is better suited
    /// to creating managed pointers to objects of allocator-aware type.
    template <class ELEMENT_TYPE, class... ARGS>
    static ManagedPtr<ELEMENT_TYPE> makeManaged(ARGS&&... args);

#endif
};

                     // ===========================
                     // struct ManagedPtrNilDeleter
                     // ===========================

/// This utility class provides a general no-op deleter, which is useful
/// when creating managed pointers to stack-allocated objects.  Note that
/// the non-template class `ManagedPtrUtil` should be used in preference to
/// this deprecated class, avoiding both template bloat and undefined
/// behavior.
///
/// @DEPRECATED: Use `ManagedPtrUtil::noOpDeleter` instead.
template <class TARGET_TYPE>
struct ManagedPtrNilDeleter {

    // CLASS METHODS

    /// Deleter function that does nothing.
    static void deleter(void *, void *);
};

             // ===========================================
             // private class ManagedPtr_FactoryDeleterType
             // ===========================================

/// This metafunction class-template provides a means to compute the
/// preferred deleter function for a factory class for those methods of
/// `ManagedPtr` that supply only a factory, and no additional deleter
/// function.  The intent is to use a common deleter function for all
/// allocators that implement the `bslma::Allocator` protocol, rather than
/// create a special deleter function based on the complete type of each
/// allocator, each doing the same thing (invoking the virtual function
/// `deleteObject`).
template <class TARGET_TYPE, class FACTORY_TYPE>
struct ManagedPtr_FactoryDeleterType
    : bsl::conditional<
                 bsl::is_convertible<FACTORY_TYPE *, Allocator *>::value,
                 ManagedPtr_FactoryDeleter<TARGET_TYPE, Allocator>,
                 ManagedPtr_FactoryDeleter<TARGET_TYPE, FACTORY_TYPE> > {
};

              // ========================================
              // private struct ManagedPtr_DefaultDeleter
              // ========================================

/// This `struct` provides a function-like managed pointer deleter that
/// invokes `delete` with the passed pointer.
template <class MANAGED_TYPE>
struct ManagedPtr_DefaultDeleter {

    // CLASS METHODS

    /// Cast the specified `ptr` to (template parameter) type
    /// `MANAGED_TYPE *`, and then call `delete` with the cast pointer.
    static void deleter(void *ptr, void *);
};

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

                      // ---------------------------------
                      // private struct ManagedPtr_ImpUtil
                      // ---------------------------------

// CLASS METHODS
template <class TYPE>
inline
void *ManagedPtr_ImpUtil::voidify(TYPE *address) BSLS_KEYWORD_NOEXCEPT
{
    return static_cast<void *>(
            const_cast<typename bsl::remove_cv<TYPE>::type *>(address));
}

template <class TYPE>
inline
TYPE *ManagedPtr_ImpUtil::unqualify(const volatile TYPE *address)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_cast<TYPE *>(address);
}

                      // ----------------------------
                      // private class ManagedPtr_Ref
                      // ----------------------------

// CREATORS
template <class TARGET_TYPE>
inline
ManagedPtr_Ref<TARGET_TYPE>::ManagedPtr_Ref(ManagedPtr_Members *base,
                                            TARGET_TYPE        *target)
: d_base_p(base)
, d_cast_p(target)
{
    BSLS_ASSERT_SAFE(0 != base);
}

template <class TARGET_TYPE>
inline
ManagedPtr_Ref<TARGET_TYPE>::~ManagedPtr_Ref()
{
    BSLS_ASSERT_SAFE(0 != d_base_p);
}

// ACCESSORS
template <class TARGET_TYPE>
inline
ManagedPtr_Members *ManagedPtr_Ref<TARGET_TYPE>::base() const
{
    return d_base_p;
}

template <class TARGET_TYPE>
inline
TARGET_TYPE *ManagedPtr_Ref<TARGET_TYPE>::target() const
{
    return d_cast_p;
}

                           // ----------------
                           // class ManagedPtr
                           // ----------------

template <class TARGET_TYPE>
class ManagedPtr<volatile TARGET_TYPE>;
    // This specialization is declared but not defined, in order to provide an
    // early compile-fail check to catch misuse of managed pointer to
    // 'volatile' types, which is explicitly called out as not supported in the
    // primary class template contract.

template <class TARGET_TYPE>
class ManagedPtr<TARGET_TYPE&>;
    // This specialization is declared but not defined, in order to provide an
    // early compile-fail check to catch misuse of managed pointer to reference
    // types, which is explicitly called out as not supported in the primary
    // class template contract.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES)
template <class TARGET_TYPE>
class ManagedPtr<TARGET_TYPE&&>;
    // This specialization is declared but not defined, in order to provide an
    // early compile-fail check to catch misuse of managed pointer to reference
    // types, which is explicitly called out as not supported in the primary
    // class template contract.
#endif

// PRIVATE CLASS METHODS
template <class TARGET_TYPE>
inline
void *ManagedPtr<TARGET_TYPE>::stripBasePointerType(TARGET_TYPE *ptr)
{
    return const_cast<void *>(static_cast<const void *>(ptr));
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE>
inline
void *
ManagedPtr<TARGET_TYPE>::stripCompletePointerType(MANAGED_TYPE *ptr)
{
    return const_cast<void *>(static_cast<const void *>(ptr));
}

// PRIVATE MANIPULATORS
template <class TARGET_TYPE>
template <class MANAGED_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::loadImp(MANAGED_TYPE *ptr,
                                      void         *cookie,
                                      DeleterFunc   deleter)
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);

    d_members.runDeleter();
    d_members.set(stripCompletePointerType(ptr), cookie, deleter);
    d_members.setAliasPtr(stripBasePointerType(ptr));
}

// CREATORS
template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr()
: d_members()
{
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(bsl::nullptr_t)
: d_members()
{
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(MANAGED_TYPE *ptr)
: d_members(stripCompletePointerType(ptr),
            0,
            &ManagedPtr_DefaultDeleter<MANAGED_TYPE>::deleter,
            stripBasePointerType(ptr))
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(ManagedPtr_Ref<TARGET_TYPE> ref)
                                                          BSLS_KEYWORD_NOEXCEPT
: d_members(*ref.base())
{
    d_members.setAliasPtr(stripBasePointerType(ref.target()));
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(ManagedPtr& original) BSLS_KEYWORD_NOEXCEPT
: d_members(original.d_members)
{
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(bslmf::MovableRef<ManagedPtr> original)
                                                          BSLS_KEYWORD_NOEXCEPT
: d_members(MoveUtil::access(original).d_members)
{
}

#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    template <class TARGET_TYPE>
    template <class BDE_OTHER_TYPE>
    inline
    ManagedPtr<TARGET_TYPE>::ManagedPtr(
            ManagedPtr<BDE_OTHER_TYPE> &&original,
            typename bsl::enable_if<bsl::is_convertible<BDE_OTHER_TYPE *,
                                                        TARGET_TYPE *>::value,
                                    ManagedPtr_TraitConstraint>::type)
        BSLS_KEYWORD_NOEXCEPT
    : d_members(original.d_members)
#elif defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
    // sun compiler version 12.3 and earlier
    template <class TARGET_TYPE>
    template <class BDE_OTHER_TYPE>
    inline
    ManagedPtr<TARGET_TYPE>::ManagedPtr(
            bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > original)
        BSLS_KEYWORD_NOEXCEPT
    : d_members(MoveUtil::access(original).d_members)
#else // c++03 except old (version <= 12.3) sun compilers
    template <class TARGET_TYPE>
    template <class BDE_OTHER_TYPE>
    inline
    ManagedPtr<TARGET_TYPE>::ManagedPtr(
            bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > original,
            typename bsl::enable_if<bsl::is_convertible<BDE_OTHER_TYPE *,
                                                        TARGET_TYPE *>::value,
                                    ManagedPtr_TraitConstraint>::type)
        BSLS_KEYWORD_NOEXCEPT
    : d_members(MoveUtil::access(original).d_members)
#endif
{
    // This constructor cannot be constrained using a type trait on old Sun
    // compilers (version <= 12.3), so we need the check here.
    #if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
        BSLMF_ASSERT((bsl::is_convertible<BDE_OTHER_TYPE *,
                                          TARGET_TYPE *>::value));
    #endif

    // To deal with the possibility of multiple inheritance, we need to
    // "correct" the target pointer.
    d_members.setAliasPtr(
        stripBasePointerType(
            static_cast<TARGET_TYPE *>(
                static_cast<BDE_OTHER_TYPE *>(
                    d_members.pointer()))));
}


template <class TARGET_TYPE>
template <class ALIASED_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(ManagedPtr<ALIASED_TYPE>&  alias,
                                    TARGET_TYPE               *ptr)
: d_members()
{
    BSLS_ASSERT_SAFE(0 != alias.get() || 0 == ptr);

    if (0 != ptr) {
        d_members.move(&alias.d_members);
        d_members.setAliasPtr(stripBasePointerType(ptr));
    }
}

template <class TARGET_TYPE>
template <class ALIASED_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(
#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
                           ManagedPtr<ALIASED_TYPE>&&                    alias,
#else
                           bslmf::MovableRef<ManagedPtr<ALIASED_TYPE> >  alias,
#endif
                           TARGET_TYPE                                  *ptr)
: d_members()
{
    ManagedPtr<ALIASED_TYPE>& lvalue = alias;

    BSLS_ASSERT_SAFE(0 != lvalue.get() || 0 == ptr);

    if (0 != ptr) {
        d_members.move(&lvalue.d_members);
        d_members.setAliasPtr(stripBasePointerType(ptr));
    }
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE, class FACTORY_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(MANAGED_TYPE *ptr, FACTORY_TYPE *factory)
: d_members(stripCompletePointerType(ptr),
            factory,
            &ManagedPtr_FactoryDeleterType<MANAGED_TYPE,
                                           FACTORY_TYPE>::type::deleter,
            stripBasePointerType(ptr))
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLS_ASSERT_SAFE(0 != factory || 0 == ptr);
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(bsl::nullptr_t, bsl::nullptr_t)
: d_members()
{
}

template <class TARGET_TYPE>
template <class FACTORY_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(bsl::nullptr_t, FACTORY_TYPE *)
: d_members()
{
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(TARGET_TYPE *ptr,
                                    void        *cookie,
                                    DeleterFunc  deleter)
: d_members(stripBasePointerType(ptr), cookie, deleter)
{
    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(MANAGED_TYPE *ptr,
                                    void         *cookie,
                                    DeleterFunc   deleter)
: d_members(stripCompletePointerType(ptr),
            cookie,
            deleter,
            stripBasePointerType(ptr))
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));

    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);
}

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
template <class TARGET_TYPE>
template <class MANAGED_TYPE, class MANAGED_BASE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(
                                MANAGED_TYPE *ptr,
                                void         *cookie,
                                void        (*deleter)(MANAGED_BASE *, void *))
: d_members(stripCompletePointerType(ptr),
            cookie,
            reinterpret_cast<DeleterFunc>(deleter),
            stripBasePointerType(ptr))
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *,
                                      const MANAGED_BASE *>::value));

    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE,
          class MANAGED_BASE,
          class COOKIE_TYPE,
          class COOKIE_BASE>
inline
ManagedPtr<TARGET_TYPE>::ManagedPtr(
                         MANAGED_TYPE *ptr,
                         COOKIE_TYPE  *cookie,
                         void        (*deleter)(MANAGED_BASE *, COOKIE_BASE *))
: d_members(stripCompletePointerType(ptr),
            static_cast<COOKIE_BASE *>(cookie),
            reinterpret_cast<DeleterFunc>(deleter),
            stripBasePointerType(ptr))
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *,
                                      const MANAGED_BASE *>::value));
    BSLMF_ASSERT((bsl::is_convertible<COOKIE_TYPE *, COOKIE_BASE *>::value));

    // Note that the undefined behavior embodied in the 'reinterpret_cast'
    // above could be removed by inserting an additional forwarding function
    // truly of type 'DeleterFunc' which 'reinterpret_cast's each pointer
    // argument as part of its forwarding behavior.  We choose not to do this
    // on the grounds of simple efficiency, and there is currently no known
    // supported compiler that we use where this does not work as desired.

    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);
}
#endif // BDE_OMIT_INTERNAL_DEPRECATED

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>::~ManagedPtr()
{
    d_members.runDeleter();
}

// MANIPULATORS
template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>&
ManagedPtr<TARGET_TYPE>::operator=(ManagedPtr& rhs)       BSLS_KEYWORD_NOEXCEPT
{
    d_members.moveAssign(&rhs.d_members);
    return *this;
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>&
ManagedPtr<TARGET_TYPE>::operator=(bslmf::MovableRef<ManagedPtr> rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    ManagedPtr& lvalue = rhs;
    d_members.moveAssign(&lvalue.d_members);
    return *this;
}

#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
    template <class TARGET_TYPE>
    template <class BDE_OTHER_TYPE>
    inline
    typename bsl::enable_if<
        bsl::is_convertible<BDE_OTHER_TYPE*, TARGET_TYPE*>::value,
        ManagedPtr<TARGET_TYPE> >::type&
    ManagedPtr<TARGET_TYPE>::operator =(
            ManagedPtr<BDE_OTHER_TYPE>&& rhs) BSLS_KEYWORD_NOEXCEPT
#elif defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
    // sun compiler version 12.3 and earlier
    template <class TARGET_TYPE>
    template <class BDE_OTHER_TYPE>
    inline
    ManagedPtr<TARGET_TYPE>&
    ManagedPtr<TARGET_TYPE>::operator =(
          bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > rhs)
        BSLS_KEYWORD_NOEXCEPT
#else // c++03 except old (version <= 12.3) sun compilers
    template <class TARGET_TYPE>
    template <class BDE_OTHER_TYPE>
    inline
    typename bsl::enable_if<
        bsl::is_convertible<BDE_OTHER_TYPE *, TARGET_TYPE *>::value,
        ManagedPtr<TARGET_TYPE> >::type&
    ManagedPtr<TARGET_TYPE>::operator =(
          bslmf::MovableRef<ManagedPtr<BDE_OTHER_TYPE> > rhs)
        BSLS_KEYWORD_NOEXCEPT
#endif
{
    // This operator cannot be constrained using a type trait on Sun, so we
    // need the check here.
    #if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
        BSLMF_ASSERT((bsl::is_convertible<BDE_OTHER_TYPE *,
                                          TARGET_TYPE *>::value));
    #endif

    ManagedPtr<BDE_OTHER_TYPE>& lvalue = rhs;
    d_members.moveAssign(&lvalue.d_members);

    // To deal with the possibility of multiple inheritance, we need to
    // "correct" the target pointer.
    d_members.setAliasPtr(
        stripBasePointerType(
            static_cast<TARGET_TYPE *>(
                static_cast<BDE_OTHER_TYPE *>(
                    d_members.pointer()))));

    return *this;
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>&
ManagedPtr<TARGET_TYPE>::operator=(ManagedPtr_Ref<TARGET_TYPE> ref)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    d_members.moveAssign(ref.base());
    d_members.setAliasPtr(stripBasePointerType(ref.target()));
    return *this;
}

template <class TARGET_TYPE>
inline
ManagedPtr<TARGET_TYPE>&
ManagedPtr<TARGET_TYPE>::operator=(bsl::nullptr_t)
{
    this->reset();
    return *this;
}

template <class TARGET_TYPE>
template <class REFERENCED_TYPE>
inline
ManagedPtr<TARGET_TYPE>::operator ManagedPtr_Ref<REFERENCED_TYPE>()
{
    BSLMF_ASSERT((bsl::is_convertible<TARGET_TYPE *,
                                      REFERENCED_TYPE *>::value));

    return ManagedPtr_Ref<REFERENCED_TYPE>(&d_members,
                             static_cast<REFERENCED_TYPE *>(
                             static_cast<TARGET_TYPE *>(d_members.pointer())));
}

template <class TARGET_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::clear()
{
    reset();
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::load(MANAGED_TYPE *ptr)
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));

    typedef ManagedPtr_FactoryDeleter<MANAGED_TYPE, Allocator> DeleterFactory;
    this->loadImp(ptr,
                  static_cast<void *>(Default::allocator()),
                  &DeleterFactory::deleter);
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE, class FACTORY_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::load(MANAGED_TYPE *ptr, FACTORY_TYPE *factory)
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLS_ASSERT_SAFE(0 != factory || 0 == ptr);

    typedef typename
    ManagedPtr_FactoryDeleterType<MANAGED_TYPE, FACTORY_TYPE>::type
                                                                DeleterFactory;

    this->loadImp(ptr, static_cast<void *>(factory), &DeleterFactory::deleter);
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::load(MANAGED_TYPE *ptr,
                                   void         *cookie,
                                   DeleterFunc   deleter)
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);

    this->loadImp(ptr, cookie, deleter);
}

template <class TARGET_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::load(bsl::nullptr_t, void *, DeleterFunc)
{
    this->reset();
}

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
template <class TARGET_TYPE>
template <class MANAGED_TYPE, class COOKIE_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::load(MANAGED_TYPE *ptr,
                                   COOKIE_TYPE  *cookie,
                                   DeleterFunc   deleter)
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);

    this->loadImp(ptr, static_cast<void *>(cookie), deleter);
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE, class MANAGED_BASE>
inline
void ManagedPtr<TARGET_TYPE>::load(
                                MANAGED_TYPE *ptr,
                                void         *cookie,
                                void        (*deleter)(MANAGED_BASE *, void *))
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLMF_ASSERT((!bsl::is_void<MANAGED_BASE>::value));
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, MANAGED_BASE *>::value));
    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);

    this->loadImp(ptr, cookie, reinterpret_cast<DeleterFunc>(deleter));
}

template <class TARGET_TYPE>
template <class MANAGED_TYPE,
          class MANAGED_BASE,
          class COOKIE_TYPE,
          class COOKIE_BASE>
inline
void ManagedPtr<TARGET_TYPE>::load(
                         MANAGED_TYPE *ptr,
                         COOKIE_TYPE  *cookie,
                         void        (*deleter)(MANAGED_BASE *, COOKIE_BASE *))
{
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, TARGET_TYPE *>::value));
    BSLMF_ASSERT((bsl::is_convertible<MANAGED_TYPE *, MANAGED_BASE *>::value));
    BSLMF_ASSERT((bsl::is_convertible<COOKIE_TYPE *, COOKIE_BASE *>::value));
    BSLS_ASSERT_SAFE(0 != deleter || 0 == ptr);

    this->loadImp(ptr,
                  static_cast<void *>(static_cast<COOKIE_BASE *>(cookie)),
                  reinterpret_cast<DeleterFunc>(deleter));
}
#endif // BDE_OMIT_INTERNAL_DEPRECATED

template <class TARGET_TYPE>
template <class ALIASED_TYPE>
void ManagedPtr<TARGET_TYPE>::loadAlias(ManagedPtr<ALIASED_TYPE>&  alias,
                                        TARGET_TYPE               *ptr)
{
    BSLS_ASSERT_SAFE(!ptr == !alias.get());  // both null or both non-null

    if (ptr && alias.d_members.pointer()) {
        d_members.moveAssign(&alias.d_members);
        d_members.setAliasPtr(stripBasePointerType(ptr));
    }
    else {
        d_members.runDeleter();
        d_members.clear();
    }
}

template <class TARGET_TYPE>
ManagedPtr_PairProxy<TARGET_TYPE, ManagedPtrDeleter>
ManagedPtr<TARGET_TYPE>::release()
{
    typedef ManagedPtr_PairProxy<TARGET_TYPE, ManagedPtrDeleter> ResultType;

    TARGET_TYPE *p = get();

    // The behavior would be undefined if 'd_members.deleter()' were called
    // when 'p' is null.

    if (p) {
        ResultType result = { p, d_members.deleter() };
        d_members.clear();
        return result;                                                // RETURN
    }
    ResultType result = { p, ManagedPtrDeleter() };
    return result;
}

template <class TARGET_TYPE>
TARGET_TYPE *ManagedPtr<TARGET_TYPE>::release(ManagedPtrDeleter *deleter)
{
    BSLS_ASSERT_SAFE(deleter);

    TARGET_TYPE *result = get();

    // The behavior is undefined if 'd_members.deleter()' is called when
    // 'result' is null.

    if (result) {
        *deleter = d_members.deleter();
        d_members.clear();
    }
    return result;
}

template <class TARGET_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::reset()
{
    d_members.runDeleter();
    d_members.clear();
}

template <class TARGET_TYPE>
inline
void ManagedPtr<TARGET_TYPE>::swap(ManagedPtr& other)
{
    d_members.swap(other.d_members);
}

// ACCESSORS
template <class TARGET_TYPE>
inline
bool ManagedPtr<TARGET_TYPE>::operator==(bsl::nullptr_t) const
{
    return !d_members.pointer();
}

template <class TARGET_TYPE>
inline
bool ManagedPtr<TARGET_TYPE>::operator!=(bsl::nullptr_t) const
{
    return d_members.pointer();
}

template <class TARGET_TYPE>
inline
#if defined(BSLS_PLATFORM_CMP_IBM)      // last confirmed with xlC 12.1
ManagedPtr<TARGET_TYPE>::operator typename ManagedPtr::BoolType() const
#else
ManagedPtr<TARGET_TYPE>::operator BoolType() const
#endif
{
    return d_members.pointer()
           ? bsls::UnspecifiedBool<ManagedPtr>::trueValue()
           : bsls::UnspecifiedBool<ManagedPtr>::falseValue();
}

template <class TARGET_TYPE>
inline
typename bslmf::AddReference<TARGET_TYPE>::Type
ManagedPtr<TARGET_TYPE>::operator*() const
{
    BSLS_ASSERT_SAFE(d_members.pointer());

    return *static_cast<TARGET_TYPE *>(d_members.pointer());
}

template <class TARGET_TYPE>
inline
TARGET_TYPE *ManagedPtr<TARGET_TYPE>::operator->() const
{
    return static_cast<TARGET_TYPE *>(d_members.pointer());
}

template <class TARGET_TYPE>
inline
const ManagedPtrDeleter& ManagedPtr<TARGET_TYPE>::deleter() const
{
    BSLS_ASSERT_SAFE(d_members.pointer());

    return d_members.deleter();
}

template <class TARGET_TYPE>
inline
TARGET_TYPE *ManagedPtr<TARGET_TYPE>::get() const
{
    return static_cast<TARGET_TYPE *>(d_members.pointer());
}

template <class TARGET_TYPE>
inline
TARGET_TYPE *ManagedPtr<TARGET_TYPE>::ptr() const
{
    return get();
}

// FREE FUNCTIONS
template <class TARGET_TYPE>
inline
void swap(ManagedPtr<TARGET_TYPE>& a, ManagedPtr<TARGET_TYPE>& b)
{
    a.swap(b);
}

                      // --------------------
                      // struct ManagedPtrUtil
                      // --------------------

template <class ELEMENT_TYPE>
inline
void ManagedPtrUtil::allocatorDeleter(void *object, void *allocator)
{
    BSLS_ASSERT(0 != object);
    BSLS_ASSERT(0 != allocator);

    AllocatorUtil::deleteObject(static_cast<Allocator *>(allocator),
                                static_cast<ELEMENT_TYPE *>(object));
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14

template <class ELEMENT_TYPE, class ALLOCATOR, class... ARGS>
inline
typename bsl::enable_if<bsl::is_class<ALLOCATOR>::value,
                        ManagedPtr<ELEMENT_TYPE> >::type
ManagedPtrUtil::allocateManaged(const ALLOCATOR& allocator, ARGS&&... args)
{
    return allocateManaged<ELEMENT_TYPE>(
                                 allocator.mechanism(),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
}

template <class ELEMENT_TYPE, class... ARGS>
inline
ManagedPtr<ELEMENT_TYPE> ManagedPtrUtil::makeManaged(ARGS&&... args)
{
    bslma::Allocator *defaultAllocator = bslma::Default::defaultAllocator();

    typedef typename bsl::remove_cv<ELEMENT_TYPE>::type UnqualElem;

    // Use 'allocateObject' with a separate construction step to avoid passing
    // the allocator to the constructed object.
    UnqualElem *objPtr =
        bslma::AllocatorUtil::allocateObject<UnqualElem>(defaultAllocator);

    bslma::DeallocateObjectProctor<bslma::Allocator *, UnqualElem> proctor(
                                                     defaultAllocator, objPtr);

    // Do not pass an allocator to the element constructor.
    ::new (ManagedPtr_ImpUtil::voidify(objPtr)) ELEMENT_TYPE(
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
    proctor.release();

    return ManagedPtr<ELEMENT_TYPE>(objPtr,
                                    defaultAllocator,
                                    &allocatorDeleter<UnqualElem>);
}

template <class ELEMENT_TYPE, class... ARGS>
inline
ManagedPtr<ELEMENT_TYPE>
ManagedPtrUtil::allocateManaged(bslma::Allocator *allocator, ARGS&&... args)
{
    typedef typename bsl::remove_cv<ELEMENT_TYPE>::type UnqualElem;

    allocator = bslma::Default::allocator(allocator);

    ELEMENT_TYPE *objPtr = bslma::AllocatorUtil::newObject<UnqualElem>(
                                 allocator,
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);

    return ManagedPtr<ELEMENT_TYPE>(objPtr,
                                    allocator,
                                    &allocatorDeleter<UnqualElem>);
}

#endif

                      // --------------------------
                      // class ManagedPtrNilDeleter
                      // --------------------------

// CLASS METHODS
template <class TARGET_TYPE>
inline
void ManagedPtrNilDeleter<TARGET_TYPE>::deleter(void *, void *)
{
}

              // ----------------------------------------
              // private struct ManagedPtr_DefaultDeleter
              // ----------------------------------------

// CLASS METHODS
template <class MANAGED_TYPE>
inline
void ManagedPtr_DefaultDeleter<MANAGED_TYPE>::deleter(void *ptr, void *)
{
    delete reinterpret_cast<MANAGED_TYPE *>(ptr);
}

}  // close package namespace

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

namespace bslmf {

template <class TARGET_TYPE>
struct HasPointerSemantics<bslma::ManagedPtr<TARGET_TYPE> > : bsl::true_type
{
};

template <class TARGET_TYPE>
struct IsBitwiseMoveable<bslma::ManagedPtr<TARGET_TYPE> > : bsl::true_type
{
};

}  // close namespace bslmf
}  // close enterprise namespace

namespace bsl {

template <class TARGET_TYPE>
struct is_nothrow_move_constructible<
    BloombergLP::bslma::ManagedPtr<TARGET_TYPE> > : bsl::true_type
{
};

}  // close namespace bsl

#endif // End C++11 code

#endif

// ----------------------------------------------------------------------------
// Copyright 2016 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 ----------------------------------
