//
// AutoPtr.h
//
// $Id: //poco/1.4/Foundation/include/Poco/AutoPtr.h#1 $
//
// Library: Foundation
// Package: Core
// Module: AutoPtr
//
// Definition of the AutoPtr template class.
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#ifndef Foundation_AutoPtr_INCLUDED
#define Foundation_AutoPtr_INCLUDED
#include "Poco/Foundation.h"
#include "Poco/Exception.h"
#include <algorithm>
#include <functional> // for std::less, greater, etc
namespace Poco {
template <class C>
class AutoPtr
/// AutoPtr is a "smart" pointer for classes implementing
/// reference counting based garbage collection.
/// To be usable with the AutoPtr template, a class must
/// implement the following behaviour:
/// A class must maintain a reference count.
/// The constructors of the object initialize the reference
/// count to one.
/// The class must implement a public duplicate() method:
/// void duplicate();
/// that increments the reference count by one.
/// The class must implement a public release() method:
/// void release()
/// that decrements the reference count by one, and,
/// if the reference count reaches zero, deletes the
/// object.
///
/// AutoPtr works in the following way:
/// If an AutoPtr is assigned an ordinary pointer to
/// an object (via the constructor or the assignment operator),
/// it takes ownership of the object and the object's reference
/// count remains unchanged.
/// If the AutoPtr is assigned another AutoPtr, the
/// object's reference count is incremented by one by
/// calling duplicate() on its object.
/// The destructor of AutoPtr calls release() on its
/// object.
/// AutoPtr supports dereferencing with both the ->
/// and the * operator. An attempt to dereference a null
/// AutoPtr results in a NullPointerException being thrown.
/// AutoPtr also implements all relational operators.
/// Note that AutoPtr allows casting of its encapsulated data types.
{
public:
AutoPtr(): _ptr(0)
{
}
AutoPtr(C* ptr): _ptr(ptr)
{
}
AutoPtr(C* ptr, bool shared): _ptr(ptr)
{
if (shared && _ptr) _ptr->duplicate();
}
AutoPtr(const AutoPtr& ptr): _ptr(ptr._ptr)
{
if (_ptr) _ptr->duplicate();
}
template <class Other>
AutoPtr(const AutoPtr<Other>& ptr): _ptr(ptr.get())
{
if (_ptr) _ptr->duplicate();
}
~AutoPtr()
{
if (_ptr) _ptr->release();
}
AutoPtr& assign(C* ptr)
{
if (_ptr != ptr)
{
if (_ptr) _ptr->release();
_ptr = ptr;
}
return *this;
}
AutoPtr& assign(C* ptr, bool shared)
{
if (_ptr != ptr)
{
if (_ptr) _ptr->release();
_ptr = ptr;
if (shared && _ptr) _ptr->duplicate();
}
return *this;
}
AutoPtr& assign(const AutoPtr& ptr)
{
if (&ptr != this)
{
if (_ptr) _ptr->release();
_ptr = ptr._ptr;
if (_ptr) _ptr->duplicate();
}
return *this;
}
template <class Other>
AutoPtr& assign(const AutoPtr<Other>& ptr)
{
if (ptr.get() != _ptr)
{
if (_ptr) _ptr->release();
_ptr = ptr.get();
if (_ptr) _ptr->duplicate();
}
return *this;
}
AutoPtr& operator = (C* ptr)
{
return assign(ptr);
}
AutoPtr& operator = (const AutoPtr& ptr)
{
return assign(ptr);
}
template <class Other>
AutoPtr& operator = (const AutoPtr<Other>& ptr)
{
return assign<Other>(ptr);
}
void swap(AutoPtr& ptr)
{
std::swap(_ptr, ptr._ptr);
}
template <class Other>
AutoPtr<Other> cast() const
/// Casts the AutoPtr via a dynamic cast to the given type.
/// Returns an AutoPtr containing NULL if the cast fails.
/// Example: (assume class Sub: public Super)
/// AutoPtr<Super> super(new Sub());
/// AutoPtr<Sub> sub = super.cast<Sub>();
/// poco_assert (sub.get());
{
Other* pOther = dynamic_cast<Other*>(_ptr);
return AutoPtr<Other>(pOther, true);
}
template <class Other>
AutoPtr<Other> unsafeCast() const
/// Casts the AutoPtr via a static cast to the given type.
/// Example: (assume class Sub: public Super)
/// AutoPtr<Super> super(new Sub());
/// AutoPtr<Sub> sub = super.unsafeCast<Sub>();
/// poco_assert (sub.get());
{
Other* pOther = static_cast<Other*>(_ptr);
return AutoPtr<Other>(pOther, true);
}
C* operator -> () const
{
if (_ptr)
return _ptr;
else
throw NullPointerException();
}
C& operator * () const
{
if (_ptr)
return *_ptr;
else
throw NullPointerException();
}
C* get() const
{
return _ptr;
}
// This also serves as an safe implicit conversion to a boolean type
operator C* () const
{
return _ptr;
}
bool operator ! () const
{
return _ptr == 0;
}
bool isNull() const
{
return _ptr == 0;
}
C* duplicate() const
{
if (_ptr) _ptr->duplicate();
return _ptr;
}
private:
C* _ptr;
};
namespace Detail {
// This class will generate a compilation error if the types T and U
// can not be compared, i.e. they do not have a a composite
// pointer type
// Intentionaly complex to reduce the likeliness of warnings
template <class T, class U>
struct EnsureHasCompositePointerType
{
static void constraints(T* a, U* b, bool& x)
{
// If you get a compilation error here, then you have
// tried to compare two smart pointers with
// unrelated types.
x = a < b;
}
typedef void f_type(T*, U*, bool&);
void no_op(f_type)
{
// empty on purpose
}
EnsureHasCompositePointerType()
{
// This assignment should be optimized away by the compiler
void (*p)(T*, U*, bool&) = constraints;
// To get rid of the warning that we do not use the
// variable
no_op(p);
}
};
// The use of EnsureHasCompositePointerType, is done to ensure that
// the pointers can be compared using the normal C++ language rules.
// The reason the operators are not used directly is because
// they are not required to give a total ordering for objects of any
// type, however the predicates, eg. std::less, are required to give
// a total ordering.
template <class T, class U>
bool pointerLess(T* a, U* b)
{
EnsureHasCompositePointerType<T, U>();
return std::less<const void*>()(a, b);
}
template <class T, class U>
bool pointerLessEq(T* a, U* b)
{
EnsureHasCompositePointerType<T, U>();
return std::less_equal<const void*>()(a, b);
}
template <class T, class U>
bool pointerGreater(T* a, U* b)
{
EnsureHasCompositePointerType<T, U>();
return std::greater<const void*>()(a, b);
}
template <class T, class U>
bool pointerGreaterEq(T* a, U* b)
{
EnsureHasCompositePointerType<T, U>();
return std::greater_equal<const void*>()(a, b);
}
}
template <class C>
inline void swap(AutoPtr<C>& p1, AutoPtr<C>& p2)
{
p1.swap(p2);
}
template <class T, class U>
bool operator == (const AutoPtr<T>& a, const AutoPtr<U>& b)
{
return a.get() == b.get();
}
template <class T, class U>
bool operator == (T* a, const AutoPtr<U>& b)
{
return a == b.get();
}
template <class T, class U>
bool operator == (const AutoPtr<T>& a, U* b)
{
return a.get() == b;
}
template <class T, class U>
bool operator != (const AutoPtr<T>& a, const AutoPtr<U>& b)
{
return a.get() != b.get();
}
template <class T, class U>
bool operator != (T* a, const AutoPtr<U>& b)
{
return a != b.get();
}
template <class T, class U>
bool operator != (const AutoPtr<T>& a, U* b)
{
return a.get() != b;
}
template <class T, class U>
bool operator < (const AutoPtr<T>& a, const AutoPtr<U>& b)
{
return Detail::pointerLess(a.get(), b.get());
}
template <class T, class U>
bool operator < (T* a, const AutoPtr<U>& b)
{
return Detail::pointerLess(a, b.get());
}
template <class T, class U>
bool operator < (const AutoPtr<T>& a, U* b)
{
return Detail::pointerLess(a.get(), b);
}
template <class T, class U>
bool operator <= (const AutoPtr<T>& a, const AutoPtr<U>& b)
{
return Detail::pointerLessEq(a.get(), b.get());
}
template <class T, class U>
bool operator <= (T* a, const AutoPtr<U>& b)
{
return Detail::pointerLessEq(a, b.get());
}
template <class T, class U>
bool operator <= (const AutoPtr<T>& a, U* b)
{
return Detail::pointerLessEq(a.get(), b);
}
template <class T, class U>
bool operator > (const AutoPtr<T>& a, const AutoPtr<U>& b)
{
return Detail::pointerGreater(a.get(), b.get());
}
template <class T, class U>
bool operator > (T* a, const AutoPtr<U>& b)
{
return Detail::pointerGreater(a, b.get());
}
template <class T, class U>
bool operator > (const AutoPtr<T>& a, U* b)
{
return Detail::pointerGreater(a.get(), b);
}
template <class T, class U>
bool operator >= (const AutoPtr<T>& a, const AutoPtr<U>& b)
{
return Detail::pointerGreaterEq(a.get(), b.get());
}
template <class T, class U>
bool operator >= (T* a, const AutoPtr<U>& b)
{
return Detail::pointerGreaterEq(a, b.get());
}
template <class T, class U>
bool operator >= (const AutoPtr<T>& a, U* b)
{
return Detail::pointerGreaterEq(a.get(), b);
}
} // namespace Poco
#endif // Foundation_AutoPtr_INCLUDED