//////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2001 by Andrei Alexandrescu // This code accompanies the book: // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design // Patterns Applied". Copyright (c) 2001. Addison-Wesley. // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author or Addison-Wesley Longman make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// #ifndef LOKI_SMARTPTR_INC_ #define LOKI_SMARTPTR_INC_ // $Id: SmartPtr.h 903 2008-11-10 05:55:12Z rich_sposato $ /// \defgroup SmartPointerGroup Smart pointers /// Policy based implementation of a smart pointer /// \defgroup SmartPointerOwnershipGroup Ownership policies /// \ingroup SmartPointerGroup /// \defgroup SmartPointerStorageGroup Storage policies /// \ingroup SmartPointerGroup /// \defgroup SmartPointerConversionGroup Conversion policies /// \ingroup SmartPointerGroup /// \defgroup SmartPointerCheckingGroup Checking policies /// \ingroup SmartPointerGroup #include "LokiExport.h" #include "SmallObj.h" #include "TypeManip.h" #include "static_check.h" #include "RefToValue.h" #include "ConstPolicy.h" #include #include #include #include #if !defined(_MSC_VER) # if defined(__sparc__) # include # else # include # endif #endif #if defined(_MSC_VER) || defined(__GNUC__) // GCC>=4.1 must use -ffriend-injection due to a bug in GCC #define LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND #endif namespace Loki { //////////////////////////////////////////////////////////////////////////////// /// \class HeapStorage /// /// \ingroup SmartPointerStorageGroup /// Implementation of the StoragePolicy used by SmartPtr. Uses explicit call /// to T's destructor followed by call to free. //////////////////////////////////////////////////////////////////////////////// template class HeapStorage { public: typedef T* StoredType; /// the type of the pointee_ object typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. typedef T* PointerType; /// type returned by operator-> typedef T& ReferenceType; /// type returned by operator* HeapStorage() : pointee_(Default()) {} // The storage policy doesn't initialize the stored pointer // which will be initialized by the OwnershipPolicy's Clone fn HeapStorage(const HeapStorage&) : pointee_(0) {} template HeapStorage(const HeapStorage&) : pointee_(0) {} HeapStorage(const StoredType& p) : pointee_(p) {} PointerType operator->() const { return pointee_; } ReferenceType operator*() const { return *pointee_; } void Swap(HeapStorage& rhs) { std::swap(pointee_, rhs.pointee_); } // Accessors template friend typename HeapStorage::PointerType GetImpl(const HeapStorage& sp); template friend const typename HeapStorage::StoredType& GetImplRef(const HeapStorage& sp); template friend typename HeapStorage::StoredType& GetImplRef(HeapStorage& sp); protected: // Destroys the data stored // (Destruction might be taken over by the OwnershipPolicy) void Destroy() { if ( 0 != pointee_ ) { pointee_->~T(); ::free( pointee_ ); } } // Default value to initialize the pointer static StoredType Default() { return 0; } private: // Data StoredType pointee_; }; template inline typename HeapStorage::PointerType GetImpl(const HeapStorage& sp) { return sp.pointee_; } template inline const typename HeapStorage::StoredType& GetImplRef(const HeapStorage& sp) { return sp.pointee_; } template inline typename HeapStorage::StoredType& GetImplRef(HeapStorage& sp) { return sp.pointee_; } //////////////////////////////////////////////////////////////////////////////// /// \class DefaultSPStorage /// /// \ingroup SmartPointerStorageGroup /// Implementation of the StoragePolicy used by SmartPtr //////////////////////////////////////////////////////////////////////////////// template class DefaultSPStorage { public: typedef T* StoredType; // the type of the pointee_ object typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. typedef T* PointerType; // type returned by operator-> typedef T& ReferenceType; // type returned by operator* DefaultSPStorage() : pointee_(Default()) {} // The storage policy doesn't initialize the stored pointer // which will be initialized by the OwnershipPolicy's Clone fn DefaultSPStorage(const DefaultSPStorage&) : pointee_(0) {} template DefaultSPStorage(const DefaultSPStorage&) : pointee_(0) {} DefaultSPStorage(const StoredType& p) : pointee_(p) {} PointerType operator->() const { return pointee_; } ReferenceType operator*() const { return *pointee_; } void Swap(DefaultSPStorage& rhs) { std::swap(pointee_, rhs.pointee_); } // Accessors template friend typename DefaultSPStorage::PointerType GetImpl(const DefaultSPStorage& sp); template friend const typename DefaultSPStorage::StoredType& GetImplRef(const DefaultSPStorage& sp); template friend typename DefaultSPStorage::StoredType& GetImplRef(DefaultSPStorage& sp); protected: // Destroys the data stored // (Destruction might be taken over by the OwnershipPolicy) // // If your compiler gives you a warning in this area while // compiling the tests, it is on purpose, please ignore it. void Destroy() { delete pointee_; } // Default value to initialize the pointer static StoredType Default() { return 0; } private: // Data StoredType pointee_; }; template inline typename DefaultSPStorage::PointerType GetImpl(const DefaultSPStorage& sp) { return sp.pointee_; } template inline const typename DefaultSPStorage::StoredType& GetImplRef(const DefaultSPStorage& sp) { return sp.pointee_; } template inline typename DefaultSPStorage::StoredType& GetImplRef(DefaultSPStorage& sp) { return sp.pointee_; } //////////////////////////////////////////////////////////////////////////////// /// \class LockedStorage /// /// \ingroup SmartPointerStorageGroup /// Implementation of the StoragePolicy used by SmartPtr. /// /// Each call to operator-> locks the object for the duration of a call to a /// member function of T. /// /// \par How It Works /// LockedStorage has a helper class called Locker, which acts as a smart /// pointer with limited abilities. LockedStorage::operator-> returns an /// unnamed temporary of type Locker that exists for the duration of the /// call to a member function of T. The unnamed temporary locks the object /// when it is constructed by operator-> and unlocks the object when it is /// destructed. /// /// \note This storage policy requires class T to have member functions Lock /// and Unlock. If your class does not have Lock or Unlock functions, you may /// either make a child class which does, or make a policy class similar to /// LockedStorage which calls other functions to lock the object. //////////////////////////////////////////////////////////////////////////////// template class Locker { public: Locker( const T* p ) : pointee_( const_cast< T* >( p ) ) { if ( pointee_ != 0 ) pointee_->Lock(); } ~Locker( void ) { if ( pointee_ != 0 ) pointee_->Unlock(); } operator T* () { return pointee_; } T* operator->() { return pointee_; } private: Locker( void ); Locker& operator = ( const Locker& ); T* pointee_; }; template class LockedStorage { public: typedef T* StoredType; /// the type of the pointee_ object typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. typedef Locker< T > PointerType; /// type returned by operator-> typedef T& ReferenceType; /// type returned by operator* LockedStorage() : pointee_( Default() ) {} ~LockedStorage( void ) {} LockedStorage( const LockedStorage&) : pointee_( 0 ) {} LockedStorage( const StoredType& p ) : pointee_( p ) {} PointerType operator->() { return Locker< T >( pointee_ ); } void Swap(LockedStorage& rhs) { std::swap( pointee_, rhs.pointee_ ); } // Accessors template friend typename LockedStorage::InitPointerType GetImpl(const LockedStorage& sp); template friend const typename LockedStorage::StoredType& GetImplRef(const LockedStorage& sp); template friend typename LockedStorage::StoredType& GetImplRef(LockedStorage& sp); protected: // Destroys the data stored // (Destruction might be taken over by the OwnershipPolicy) void Destroy() { delete pointee_; } // Default value to initialize the pointer static StoredType Default() { return 0; } private: /// Dereference operator is not implemented. ReferenceType operator*(); // Data StoredType pointee_; }; template inline typename LockedStorage::InitPointerType GetImpl(const LockedStorage& sp) { return sp.pointee_; } template inline const typename LockedStorage::StoredType& GetImplRef(const LockedStorage& sp) { return sp.pointee_; } template inline typename LockedStorage::StoredType& GetImplRef(LockedStorage& sp) { return sp.pointee_; } //////////////////////////////////////////////////////////////////////////////// /// \class ArrayStorage /// /// \ingroup SmartPointerStorageGroup /// Implementation of the ArrayStorage used by SmartPtr //////////////////////////////////////////////////////////////////////////////// template class ArrayStorage { public: typedef T* StoredType; // the type of the pointee_ object typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. typedef T* PointerType; // type returned by operator-> typedef T& ReferenceType; // type returned by operator* ArrayStorage() : pointee_(Default()) {} // The storage policy doesn't initialize the stored pointer // which will be initialized by the OwnershipPolicy's Clone fn ArrayStorage(const ArrayStorage&) : pointee_(0) {} template ArrayStorage(const ArrayStorage&) : pointee_(0) {} ArrayStorage(const StoredType& p) : pointee_(p) {} PointerType operator->() const { return pointee_; } ReferenceType operator*() const { return *pointee_; } void Swap(ArrayStorage& rhs) { std::swap(pointee_, rhs.pointee_); } // Accessors template friend typename ArrayStorage::PointerType GetImpl(const ArrayStorage& sp); template friend const typename ArrayStorage::StoredType& GetImplRef(const ArrayStorage& sp); template friend typename ArrayStorage::StoredType& GetImplRef(ArrayStorage& sp); protected: // Destroys the data stored // (Destruction might be taken over by the OwnershipPolicy) void Destroy() { delete [] pointee_; } // Default value to initialize the pointer static StoredType Default() { return 0; } private: // Data StoredType pointee_; }; template inline typename ArrayStorage::PointerType GetImpl(const ArrayStorage& sp) { return sp.pointee_; } template inline const typename ArrayStorage::StoredType& GetImplRef(const ArrayStorage& sp) { return sp.pointee_; } template inline typename ArrayStorage::StoredType& GetImplRef(ArrayStorage& sp) { return sp.pointee_; } //////////////////////////////////////////////////////////////////////////////// /// \class RefCounted /// /// \ingroup SmartPointerOwnershipGroup /// Implementation of the OwnershipPolicy used by SmartPtr /// Provides a classic external reference counting implementation //////////////////////////////////////////////////////////////////////////////// template class RefCounted { public: RefCounted() : pCount_(static_cast( SmallObject<>::operator new(sizeof(uintptr_t)))) { assert(pCount_ != 0); *pCount_ = 1; } RefCounted(const RefCounted& rhs) : pCount_(rhs.pCount_) {} // MWCW lacks template friends, hence the following kludge template RefCounted(const RefCounted& rhs) : pCount_(reinterpret_cast(rhs).pCount_) {} P Clone(const P& val) { ++*pCount_; return val; } bool Release(const P&) { if (!--*pCount_) { SmallObject<>::operator delete(pCount_, sizeof(uintptr_t)); pCount_ = NULL; return true; } return false; } void Swap(RefCounted& rhs) { std::swap(pCount_, rhs.pCount_); } enum { destructiveCopy = false }; private: // Data uintptr_t* pCount_; }; //////////////////////////////////////////////////////////////////////////////// /// \struct RefCountedMT /// /// \ingroup SmartPointerOwnershipGroup /// Implementation of the OwnershipPolicy used by SmartPtr /// Implements external reference counting for multithreaded programs /// Policy Usage: RefCountedMTAdj::RefCountedMT /// /// \par Warning /// There could be a race condition, see bug "Race condition in RefCountedMTAdj::Release" /// http://sourceforge.net/tracker/index.php?func=detail&aid=1408845&group_id=29557&atid=396644 /// As stated in bug 1408845, the Release function is not thread safe if a /// SmartPtr copy-constructor tries to copy the last pointer to an object in /// one thread, while the destructor is acting on the last pointer in another /// thread. The existence of a race between a copy-constructor and destructor /// implies a design flaw at a higher level. That race condition must be /// fixed at a higher design level, and no change to this class could fix it. //////////////////////////////////////////////////////////////////////////////// template < template class ThreadingModel, class MX = LOKI_DEFAULT_MUTEX > struct RefCountedMTAdj { template class RefCountedMT : public ThreadingModel< RefCountedMT

, MX > { typedef ThreadingModel< RefCountedMT

, MX > base_type; typedef typename base_type::IntType CountType; typedef volatile CountType* CountPtrType; public: RefCountedMT() { pCount_ = static_cast( SmallObject::operator new( sizeof(*pCount_))); assert(pCount_); //*pCount_ = 1; ThreadingModel::AtomicAssign(*pCount_, 1); } RefCountedMT(const RefCountedMT& rhs) : pCount_(rhs.pCount_) {} //MWCW lacks template friends, hence the following kludge template RefCountedMT(const RefCountedMT& rhs) : pCount_(reinterpret_cast&>(rhs).pCount_) {} P Clone(const P& val) { ThreadingModel::AtomicIncrement(*pCount_); return val; } bool Release(const P&) { bool isZero = false; ThreadingModel< RefCountedMT, MX >::AtomicDecrement( *pCount_, 0, isZero ); if ( isZero ) { SmallObject::operator delete( const_cast(pCount_), sizeof(*pCount_)); return true; } return false; } void Swap(RefCountedMT& rhs) { std::swap(pCount_, rhs.pCount_); } enum { destructiveCopy = false }; private: // Data CountPtrType pCount_; }; }; //////////////////////////////////////////////////////////////////////////////// /// \class COMRefCounted /// /// \ingroup SmartPointerOwnershipGroup /// Implementation of the OwnershipPolicy used by SmartPtr /// Adapts COM intrusive reference counting to OwnershipPolicy-specific syntax //////////////////////////////////////////////////////////////////////////////// template class COMRefCounted { public: COMRefCounted() {} template COMRefCounted(const COMRefCounted&) {} static P Clone(const P& val) { if (val != 0) val->AddRef(); return val; } static bool Release(const P& val) { if (val != 0) val->Release(); return false; } enum { destructiveCopy = false }; static void Swap(COMRefCounted&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct DeepCopy /// /// \ingroup SmartPointerOwnershipGroup /// Implementation of the OwnershipPolicy used by SmartPtr /// Implements deep copy semantics, assumes existence of a Clone() member /// function of the pointee type //////////////////////////////////////////////////////////////////////////////// template struct DeepCopy { DeepCopy() {} template DeepCopy(const DeepCopy&) {} static P Clone(const P& val) { return val->Clone(); } static bool Release(const P&) { return true; } static void Swap(DeepCopy&) {} enum { destructiveCopy = false }; }; //////////////////////////////////////////////////////////////////////////////// /// \class RefLinked /// /// \ingroup SmartPointerOwnershipGroup /// Implementation of the OwnershipPolicy used by SmartPtr /// Implements reference linking //////////////////////////////////////////////////////////////////////////////// namespace Private { class LOKI_EXPORT RefLinkedBase { public: RefLinkedBase() { prev_ = next_ = this; } RefLinkedBase(const RefLinkedBase& rhs); bool Release(); void Swap(RefLinkedBase& rhs); bool Merge( RefLinkedBase& rhs ); enum { destructiveCopy = false }; private: static unsigned int CountPrevCycle( const RefLinkedBase* pThis ); static unsigned int CountNextCycle( const RefLinkedBase* pThis ); bool HasPrevNode( const RefLinkedBase* p ) const; bool HasNextNode( const RefLinkedBase* p ) const; mutable const RefLinkedBase* prev_; mutable const RefLinkedBase* next_; }; } template class RefLinked : public Private::RefLinkedBase { public: RefLinked() {} template RefLinked(const RefLinked& rhs) : Private::RefLinkedBase(rhs) {} static P Clone(const P& val) { return val; } bool Release(const P&) { return Private::RefLinkedBase::Release(); } template < class P1 > bool Merge( RefLinked< P1 > & rhs ) { return Private::RefLinkedBase::Merge( rhs ); } }; //////////////////////////////////////////////////////////////////////////////// /// \class DestructiveCopy /// /// \ingroup SmartPointerOwnershipGroup /// Implementation of the OwnershipPolicy used by SmartPtr /// Implements destructive copy semantics (a la std::auto_ptr) //////////////////////////////////////////////////////////////////////////////// template class DestructiveCopy { public: DestructiveCopy() {} template DestructiveCopy(const DestructiveCopy&) {} template static P Clone(P1& val) { P result(val); val = P1(); return result; } static bool Release(const P&) { return true; } static void Swap(DestructiveCopy&) {} enum { destructiveCopy = true }; }; //////////////////////////////////////////////////////////////////////////////// /// \class NoCopy /// /// \ingroup SmartPointerOwnershipGroup /// Implementation of the OwnershipPolicy used by SmartPtr /// Implements a policy that doesn't allow copying objects //////////////////////////////////////////////////////////////////////////////// template class NoCopy { public: NoCopy() {} template NoCopy(const NoCopy&) {} static P Clone(const P&) { // Make it depended on template parameter static const bool DependedFalse = sizeof(P*) == 0; LOKI_STATIC_CHECK(DependedFalse, This_Policy_Disallows_Value_Copying); } static bool Release(const P&) { return true; } static void Swap(NoCopy&) {} enum { destructiveCopy = false }; }; //////////////////////////////////////////////////////////////////////////////// /// \struct AllowConversion /// /// \ingroup SmartPointerConversionGroup /// Implementation of the ConversionPolicy used by SmartPtr /// Allows implicit conversion from SmartPtr to the pointee type //////////////////////////////////////////////////////////////////////////////// struct AllowConversion { enum { allow = true }; void Swap(AllowConversion&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct DisallowConversion /// /// \ingroup SmartPointerConversionGroup /// Implementation of the ConversionPolicy used by SmartPtr /// Does not allow implicit conversion from SmartPtr to the pointee type /// You can initialize a DisallowConversion with an AllowConversion //////////////////////////////////////////////////////////////////////////////// struct DisallowConversion { DisallowConversion() {} DisallowConversion(const AllowConversion&) {} enum { allow = false }; void Swap(DisallowConversion&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct NoCheck /// /// \ingroup SmartPointerCheckingGroup /// Implementation of the CheckingPolicy used by SmartPtr /// Well, it's clear what it does :o) //////////////////////////////////////////////////////////////////////////////// template struct NoCheck { NoCheck() {} template NoCheck(const NoCheck&) {} static void OnDefault(const P&) {} static void OnInit(const P&) {} static void OnDereference(const P&) {} static void Swap(NoCheck&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct AssertCheck /// /// \ingroup SmartPointerCheckingGroup /// Implementation of the CheckingPolicy used by SmartPtr /// Checks the pointer before dereference //////////////////////////////////////////////////////////////////////////////// template struct AssertCheck { AssertCheck() {} template AssertCheck(const AssertCheck&) {} template AssertCheck(const NoCheck&) {} static void OnDefault(const P&) {} static void OnInit(const P&) {} static void OnDereference(P val) { assert(val); (void)val; } static void Swap(AssertCheck&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct AssertCheckStrict /// /// \ingroup SmartPointerCheckingGroup /// Implementation of the CheckingPolicy used by SmartPtr /// Checks the pointer against zero upon initialization and before dereference /// You can initialize an AssertCheckStrict with an AssertCheck //////////////////////////////////////////////////////////////////////////////// template struct AssertCheckStrict { AssertCheckStrict() {} template AssertCheckStrict(const AssertCheckStrict&) {} template AssertCheckStrict(const AssertCheck&) {} template AssertCheckStrict(const NoCheck&) {} static void OnDefault(P val) { assert(val); } static void OnInit(P val) { assert(val); } static void OnDereference(P val) { assert(val); } static void Swap(AssertCheckStrict&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct NullPointerException /// /// \ingroup SmartPointerGroup /// Used by some implementations of the CheckingPolicy used by SmartPtr //////////////////////////////////////////////////////////////////////////////// struct NullPointerException : public std::runtime_error { NullPointerException() : std::runtime_error(std::string("")) { } const char* what() const throw() { return "Null Pointer Exception"; } }; //////////////////////////////////////////////////////////////////////////////// /// \struct RejectNullStatic /// /// \ingroup SmartPointerCheckingGroup /// Implementation of the CheckingPolicy used by SmartPtr /// Checks the pointer upon initialization and before dereference //////////////////////////////////////////////////////////////////////////////// template struct RejectNullStatic { RejectNullStatic() {} template RejectNullStatic(const RejectNullStatic&) {} template RejectNullStatic(const NoCheck&) {} template RejectNullStatic(const AssertCheck&) {} template RejectNullStatic(const AssertCheckStrict&) {} static void OnDefault(const P&) { // Make it depended on template parameter static const bool DependedFalse = sizeof(P*) == 0; LOKI_STATIC_CHECK(DependedFalse, ERROR_This_Policy_Does_Not_Allow_Default_Initialization); } static void OnInit(const P& val) { if (!val) throw NullPointerException(); } static void OnDereference(const P& val) { if (!val) throw NullPointerException(); } static void Swap(RejectNullStatic&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct RejectNull /// /// \ingroup SmartPointerCheckingGroup /// Implementation of the CheckingPolicy used by SmartPtr /// Checks the pointer before dereference //////////////////////////////////////////////////////////////////////////////// template struct RejectNull { RejectNull() {} template RejectNull(const RejectNull&) {} static void OnInit(P) {} static void OnDefault(P) {} void OnDereference(P val) { if (!val) throw NullPointerException(); } void OnDereference(P val) const { if (!val) throw NullPointerException(); } void Swap(RejectNull&) {} }; //////////////////////////////////////////////////////////////////////////////// /// \struct RejectNullStrict /// /// \ingroup SmartPointerCheckingGroup /// Implementation of the CheckingPolicy used by SmartPtr /// Checks the pointer upon initialization and before dereference //////////////////////////////////////////////////////////////////////////////// template struct RejectNullStrict { RejectNullStrict() {} template RejectNullStrict(const RejectNullStrict&) {} template RejectNullStrict(const RejectNull&) {} static void OnInit(P val) { if (!val) throw NullPointerException(); } void OnDereference(P val) { OnInit(val); } void OnDereference(P val) const { OnInit(val); } void Swap(RejectNullStrict&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template SmartPtr (declaration) // The reason for all the fuss above //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OwnershipPolicy = RefCounted, class ConversionPolicy = DisallowConversion, template class CheckingPolicy = AssertCheck, template class StoragePolicy = DefaultSPStorage, template class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS > class SmartPtr; //////////////////////////////////////////////////////////////////////////////// // class template SmartPtrDef (definition) // this class added to unify the usage of SmartPtr // instead of writing SmartPtr write SmartPtrDef::type //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OwnershipPolicy = RefCounted, class ConversionPolicy = DisallowConversion, template class CheckingPolicy = AssertCheck, template class StoragePolicy = DefaultSPStorage, template class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS > struct SmartPtrDef { typedef SmartPtr < T, OwnershipPolicy, ConversionPolicy, CheckingPolicy, StoragePolicy, ConstnessPolicy > type; }; //////////////////////////////////////////////////////////////////////////////// /// \class SmartPtr /// /// \ingroup SmartPointerGroup /// /// \param OwnershipPolicy default = RefCounted, /// \param ConversionPolicy default = DisallowConversion, /// \param CheckingPolicy default = AssertCheck, /// \param StoragePolicy default = DefaultSPStorage /// \param ConstnessPolicy default = LOKI_DEFAULT_CONSTNESS /// /// \par IMPORTANT NOTE /// Due to threading issues, the OwnershipPolicy has been changed as follows: /// /// - Release() returns a boolean saying if that was the last release /// so the pointer can be deleted by the StoragePolicy /// - IsUnique() was removed //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OwnershipPolicy, class ConversionPolicy, template class CheckingPolicy, template class StoragePolicy, template class ConstnessPolicy > class SmartPtr : public StoragePolicy , public OwnershipPolicy::InitPointerType> , public CheckingPolicy::StoredType> , public ConversionPolicy { typedef StoragePolicy SP; typedef OwnershipPolicy::InitPointerType> OP; typedef CheckingPolicy::StoredType> KP; typedef ConversionPolicy CP; public: typedef typename ConstnessPolicy::Type* ConstPointerType; typedef typename ConstnessPolicy::Type& ConstReferenceType; typedef typename SP::PointerType PointerType; typedef typename SP::StoredType StoredType; typedef typename SP::ReferenceType ReferenceType; typedef typename Select::Result CopyArg; private: struct NeverMatched {}; #ifdef LOKI_SMARTPTR_CONVERSION_CONSTRUCTOR_POLICY typedef typename Select< CP::allow, const StoredType&, NeverMatched>::Result ImplicitArg; typedef typename Select < !CP::allow, const StoredType&, NeverMatched >::Result ExplicitArg; #else typedef const StoredType& ImplicitArg; typedef typename Select::Result ExplicitArg; #endif public: SmartPtr() { KP::OnDefault(GetImpl(*this)); } explicit SmartPtr(ExplicitArg p) : SP(p) { KP::OnInit(GetImpl(*this)); } SmartPtr(ImplicitArg p) : SP(p) { KP::OnInit(GetImpl(*this)); } SmartPtr(CopyArg& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > SmartPtr(const SmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > SmartPtr(SmartPtr& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } SmartPtr(RefToValue rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) {} operator RefToValue() { return RefToValue(*this); } SmartPtr& operator=(CopyArg& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > SmartPtr& operator=(const SmartPtr& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > SmartPtr& operator=(SmartPtr& rhs) { SmartPtr temp(rhs); temp.Swap(*this); return *this; } void Swap(SmartPtr& rhs) { OP::Swap(rhs); CP::Swap(rhs); KP::Swap(rhs); SP::Swap(rhs); } ~SmartPtr() { if (OP::Release(GetImpl(*static_cast(this)))) { SP::Destroy(); } } #ifdef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND // old non standard in class definition of friends friend inline void Release(SmartPtr& sp, typename SP::StoredType& p) { p = GetImplRef(sp); GetImplRef(sp) = SP::Default(); } friend inline void Reset(SmartPtr& sp, typename SP::StoredType p) { SmartPtr(p).Swap(sp); } #else template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > friend void Release(SmartPtr& sp, typename SP1::StoredType& p); template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > friend void Reset(SmartPtr& sp, typename SP1::StoredType p); #endif template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > bool Merge( SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) { if ( GetImpl( *this ) != GetImpl( rhs ) ) { return false; } return OP::template Merge( rhs ); } PointerType operator->() { KP::OnDereference(GetImplRef(*this)); return SP::operator->(); } ConstPointerType operator->() const { KP::OnDereference(GetImplRef(*this)); return SP::operator->(); } ReferenceType operator*() { KP::OnDereference(GetImplRef(*this)); return SP::operator*(); } ConstReferenceType operator*() const { KP::OnDereference(GetImplRef(*this)); return SP::operator*(); } bool operator!() const // Enables "if (!sp) ..." { return GetImpl(*this) == 0; } static inline T* GetPointer( const SmartPtr& sp ) { return GetImpl( sp ); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > bool operator==(const SmartPtr& rhs) const { return GetImpl(*this) == GetImpl(rhs); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > bool operator!=(const SmartPtr& rhs) const { return !(*this == rhs); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > bool operator<(const SmartPtr& rhs) const { return GetImpl(*this) < GetImpl(rhs); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > inline bool operator > ( const SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) { return ( GetImpl( rhs ) < GetImpl( *this ) ); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > inline bool operator <= ( const SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) { return !( GetImpl( rhs ) < GetImpl( *this ) ); } // Ambiguity buster template < typename T1, template class OP1, class CP1, template class KP1, template class SP1, template class CNP1 > inline bool operator >= ( const SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) { return !( GetImpl( *this ) < GetImpl( rhs ) ); } private: // Helper for enabling 'if (sp)' struct Tester { Tester(int) {} void dummy() {} }; typedef void (Tester::*unspecified_boolean_type_)(); typedef typename Select::Result unspecified_boolean_type; public: // enable 'if (sp)' operator unspecified_boolean_type() const { return !*this ? 0 : &Tester::dummy; } private: // Helper for disallowing automatic conversion struct Insipid { Insipid(PointerType) {} }; typedef typename Select::Result AutomaticConversionResult; public: operator AutomaticConversionResult() const { return GetImpl(*this); } }; //////////////////////////////////////////////////////////////////////////////// // friends //////////////////////////////////////////////////////////////////////////////// #ifndef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP > inline void Release(SmartPtr& sp, typename SP::StoredType& p) { p = GetImplRef(sp); GetImplRef(sp) = SP::Default(); } template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP > inline void Reset(SmartPtr& sp, typename SP::StoredType p) { SmartPtr(p).Swap(sp); } #endif //////////////////////////////////////////////////////////////////////////////// // free comparison operators for class template SmartPtr //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// operator== for lhs = SmartPtr, rhs = raw pointer /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP1, typename U > inline bool operator==(const SmartPtr& lhs, U* rhs) { return GetImpl(lhs) == rhs; } //////////////////////////////////////////////////////////////////////////////// /// operator== for lhs = raw pointer, rhs = SmartPtr /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP1, typename U > inline bool operator==(U* lhs, const SmartPtr& rhs) { return rhs == lhs; } //////////////////////////////////////////////////////////////////////////////// /// operator!= for lhs = SmartPtr, rhs = raw pointer /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator!=(const SmartPtr& lhs, U* rhs) { return !(lhs == rhs); } //////////////////////////////////////////////////////////////////////////////// /// operator!= for lhs = raw pointer, rhs = SmartPtr /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator!=(U* lhs, const SmartPtr& rhs) { return rhs != lhs; } //////////////////////////////////////////////////////////////////////////////// /// operator< for lhs = SmartPtr, rhs = raw pointer /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator<(const SmartPtr& lhs, U* rhs) { return ( GetImpl( lhs ) < rhs ); } //////////////////////////////////////////////////////////////////////////////// /// operator< for lhs = raw pointer, rhs = SmartPtr /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator<(U* lhs, const SmartPtr& rhs) { return ( GetImpl( rhs ) < lhs ); } //////////////////////////////////////////////////////////////////////////////// // operator> for lhs = SmartPtr, rhs = raw pointer /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator>(const SmartPtr& lhs, U* rhs) { return rhs < lhs; } //////////////////////////////////////////////////////////////////////////////// /// operator> for lhs = raw pointer, rhs = SmartPtr /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator>(U* lhs, const SmartPtr& rhs) { return rhs < lhs; } //////////////////////////////////////////////////////////////////////////////// /// operator<= for lhs = SmartPtr, rhs = raw pointer /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator<=(const SmartPtr& lhs, U* rhs) { return !(rhs < lhs); } //////////////////////////////////////////////////////////////////////////////// /// operator<= for lhs = raw pointer, rhs = SmartPtr /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator<=(U* lhs, const SmartPtr& rhs) { return !(rhs < lhs); } //////////////////////////////////////////////////////////////////////////////// /// operator>= for lhs = SmartPtr, rhs = raw pointer /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator>=(const SmartPtr& lhs, U* rhs) { return !(lhs < rhs); } //////////////////////////////////////////////////////////////////////////////// /// operator>= for lhs = raw pointer, rhs = SmartPtr /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP, typename U > inline bool operator>=(U* lhs, const SmartPtr& rhs) { return !(lhs < rhs); } } // namespace Loki //////////////////////////////////////////////////////////////////////////////// /// specialization of std::less for SmartPtr /// \ingroup SmartPointerGroup //////////////////////////////////////////////////////////////////////////////// namespace std { template < typename T, template class OP, class CP, template class KP, template class SP, template class CNP > struct less< Loki::SmartPtr > : public binary_function < Loki::SmartPtr, Loki::SmartPtr, bool > { bool operator()(const Loki::SmartPtr& lhs, const Loki::SmartPtr& rhs) const { return less()(GetImpl(lhs), GetImpl(rhs)); } }; } #endif // end file guardian