diff --git a/include/loki/StrongPtr.h b/include/loki/StrongPtr.h index 76b9712..6f8f2b1 100644 --- a/include/loki/StrongPtr.h +++ b/include/loki/StrongPtr.h @@ -58,9 +58,9 @@ /// -# explicit YourPolicy( bool strong ) /// -# YourPolicy( void * p, bool strong ) /// -# YourPolicy( const YourPolicy & rhs, bool strong ) +/// -# YourPolicy( const YourPolicy & rhs, bool isNull, bool strong ) +/// -# ~YourPolicy( void ) /// -# bool Release( bool strong ) -/// -# void Increment( bool strong ) -/// -# bool Decrement( bool strong ) /// -# bool HasStrongPointer( void ) const /// -# void Swap( YourPolicy & rhs ) /// -# void SetPointer( void * p ) @@ -100,11 +100,11 @@ /// /// \par Writing Your Own ResetPolicy /// If you write your own policy, you must implement these 2 functions: -/// -# bool OnReleaseAll( bool ) const -/// -# bool OnResetAll( bool ) const -/// The bool parameter means that this was called with a strong pointer or -/// one of its copointers is strong. The return value means the pointer -/// can be reset or released. +/// -# bool OnReleaseAll( bool, bool ) const +/// -# bool OnResetAll( bool, bool ) const +/// The first bool parameter is true if the pointer which called the function +/// is strong. The second parameter is true if any copointer is strong. The +/// return value means the pointer can be reset or released. /// /// \defgroup StrongPointerOwnershipGroup StrongPtr Ownership policies /// \ingroup SmartPointerGroup @@ -118,6 +118,9 @@ namespace Loki { +static const char * const StrongPtr_Single_Owner_Exception_Message = + "Object has more than one Owner - which violates the single owner policy for StrongPtr!"; + //////////////////////////////////////////////////////////////////////////////// /// \class DeleteUsingFree @@ -250,14 +253,41 @@ public: template < class P > struct CantResetWithStrong { - inline bool OnReleaseAll( bool hasStrongPtr ) const + inline bool OnReleaseAll( bool isThisStrong, bool isAnyStrong ) const { - return ! hasStrongPtr; + (void)isThisStrong; + return ! isAnyStrong; } - inline bool OnResetAll( bool hasStrongPtr ) const + inline bool OnResetAll( bool isThisStrong, bool isAnyStrong ) const { - return ! hasStrongPtr; + (void)isThisStrong; + return ! isAnyStrong; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class OnlyStrongMayReset +/// +/// \ingroup StrongPointerResetGroup +/// Implementation of the ResetPolicy used by StrongPtr. It only allows a +/// a strong co-pointer to reset or release. This policy was made for use with +/// the single-owner policies. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +struct OnlyStrongMayReset +{ + inline bool OnReleaseAll( bool isThisStrong, bool isAnyStrong ) const + { + (void)isAnyStrong; + return isThisStrong; + } + + inline bool OnResetAll( bool isThisStrong, bool isAnyStrong ) const + { + (void)isAnyStrong; + return isThisStrong; } }; @@ -272,12 +302,16 @@ struct CantResetWithStrong template < class P > struct AllowReset { - inline bool OnReleaseAll( bool ) const + inline bool OnReleaseAll( bool isThisStrong, bool isAnyStrong ) const { + (void)isThisStrong; + (void)isAnyStrong; return true; } - inline bool OnResetAll( bool ) const + inline bool OnResetAll( bool isThisStrong, bool isAnyStrong ) const { + (void)isThisStrong; + (void)isAnyStrong; return true; } }; @@ -293,18 +327,26 @@ struct AllowReset template < class P > struct NeverReset { - inline bool OnReleaseAll( bool ) const + inline bool OnReleaseAll( bool isThisStrong, bool isAnyStrong ) const { + (void)isThisStrong; + (void)isAnyStrong; return false; } - inline bool OnResetAll( bool ) const + inline bool OnResetAll( bool isThisStrong, bool isAnyStrong ) const { + (void)isThisStrong; + (void)isAnyStrong; return false; } }; // ---------------------------------------------------------------------------- +// Forward declaration needed for pointer to single-owner strong pointer. +class SingleOwnerRefCount; +class Lockable1OwnerRefCount; + namespace Private { @@ -399,6 +441,8 @@ public: } private: + /// Default constructor not implemented. + TwoRefCountInfo( void ); /// Copy-constructor not implemented. TwoRefCountInfo( const TwoRefCountInfo & ); /// Copy-assignment operator not implemented. @@ -409,6 +453,105 @@ private: unsigned int m_weakCount; }; +//////////////////////////////////////////////////////////////////////////////// +/// \class OneOwnerRefCountInfo +/// +/// \ingroup StrongPointerOwnershipGroup +/// Implementation detail for reference counting strong and weak pointers. +/// It maintains a void pointer and 2 reference counts. Since it is just a +/// class for managing implementation details, it is not intended to be used +/// directly - which is why it is in a private namespace. Each instance is a +/// shared resource for all copointers, and there should be only one of these +/// for each set of copointers. This class is small, trivial, and inline. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT OneOwnerRefCountInfo +{ +public: + + explicit OneOwnerRefCountInfo( SingleOwnerRefCount * ptr ); + + OneOwnerRefCountInfo( const void * p, SingleOwnerRefCount * ptr ); + + inline ~OneOwnerRefCountInfo( void ) + { + assert( NULL == m_strongPtr ); + assert( 0 == m_weakCount ); + } + + inline bool HasStrongPointer( void ) const + { + return ( NULL != m_strongPtr ); + } + + inline const SingleOwnerRefCount * GetStrongCoPointer( void ) const + { + return m_strongPtr; + } + + inline SingleOwnerRefCount * GetStrongCoPointer( void ) + { + return m_strongPtr; + } + + void SetStrongCoPtr( SingleOwnerRefCount * ptr ); + + inline bool HasWeakPointer( void ) const + { + return ( 0 < m_weakCount ); + } + + inline unsigned int GetWeakCount( void ) const + { + return m_weakCount; + } + + inline void IncWeakCount( void ) + { + ++m_weakCount; + } + + inline void DecWeakCount( void ) + { + assert( 0 < m_weakCount ); + --m_weakCount; + } + + inline void ZapPointer( void ) + { + m_pointer = NULL; + } + + void SetPointer( void * p ) + { + m_pointer = p; + } + + inline void * GetPointer( void ) const + { + return const_cast< void * >( m_pointer ); + } + + inline void * & GetPointerRef( void ) const + { + return const_cast< void * & >( m_pointer ); + } + +private: + /// Default constructor not implemented. + OneOwnerRefCountInfo( void ); + /// Copy constructor not implemented. + OneOwnerRefCountInfo( const OneOwnerRefCountInfo & ); + /// Copy-assignment operator not implemented. + OneOwnerRefCountInfo & operator = ( const OneOwnerRefCountInfo & ); + + const void * m_pointer; + SingleOwnerRefCount * m_strongPtr; + unsigned int m_weakCount; +}; + +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + //////////////////////////////////////////////////////////////////////////////// /// \class LockableTwoRefCountInfo /// @@ -427,8 +570,6 @@ private: /// do run properly. //////////////////////////////////////////////////////////////////////////////// -#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) - class LOKI_EXPORT LockableTwoRefCountInfo : private Loki::Private::TwoRefCountInfo { @@ -540,6 +681,154 @@ private: mutable LOKI_DEFAULT_MUTEX m_Mutex; }; +//////////////////////////////////////////////////////////////////////////////// +/// \class Lockable1OwnerRefCountInfo +/// +/// \ingroup StrongPointerOwnershipGroup +/// Implementation detail for thread-safe reference counting for 1 strong and +/// multiple weak pointers. It uses OneOwnerRefCountInfo to manage the pointers +/// and count. All this does is provide a thread safety mechanism. Since it +/// is just a class for managing implementation details, it is not intended to +/// be used directly - which is why it is in a private namespace. Each instance +/// is a shared resource for all copointers, and there should be only one of +/// these for each set of copointers. This class is small, trivial, and inline. +/// +/// \note This class is not designed for use with a single-threaded model. +/// Tests using a single-threaded model will not run properly, but tests in a +/// multi-threaded model with either class-level-locking or object-level-locking +/// do run properly. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT Lockable1OwnerRefCountInfo + : private Loki::Private::OneOwnerRefCountInfo +{ +public: + + explicit Lockable1OwnerRefCountInfo( Lockable1OwnerRefCount * ptr ) + : OneOwnerRefCountInfo( reinterpret_cast< SingleOwnerRefCount * >( ptr ) ) + , m_Mutex() + { + } + + Lockable1OwnerRefCountInfo( const void * p, Lockable1OwnerRefCount * ptr ) + : OneOwnerRefCountInfo( p, + reinterpret_cast< SingleOwnerRefCount * >( ptr ) ) + , m_Mutex() + { + } + + inline ~Lockable1OwnerRefCountInfo( void ) + { + } + + inline void Lock( void ) const + { + m_Mutex.Lock(); + } + + inline void Unlock( void ) const + { + m_Mutex.Unlock(); + } + + inline const Lockable1OwnerRefCount * GetStrongCoPointer( void ) const + { + m_Mutex.Lock(); + const SingleOwnerRefCount * ptr = + OneOwnerRefCountInfo::GetStrongCoPointer(); + m_Mutex.Unlock(); + return reinterpret_cast< const Lockable1OwnerRefCount * >( ptr ); + } + + inline Lockable1OwnerRefCount * GetStrongCoPointer( void ) + { + m_Mutex.Lock(); + SingleOwnerRefCount * ptr = OneOwnerRefCountInfo::GetStrongCoPointer(); + m_Mutex.Unlock(); + return reinterpret_cast< Lockable1OwnerRefCount * >( ptr ); + } + + inline void SetStrongCoPtr( Lockable1OwnerRefCount * ptr ) + { + m_Mutex.Lock(); + SingleOwnerRefCount * p = reinterpret_cast< SingleOwnerRefCount * >( ptr ); + OneOwnerRefCountInfo::SetStrongCoPtr( p ); + m_Mutex.Unlock(); + } + + inline bool HasStrongPointer( void ) const + { + m_Mutex.Lock(); + const bool has = OneOwnerRefCountInfo::HasStrongPointer(); + m_Mutex.Unlock(); + return has; + } + + inline unsigned int GetWeakCount( void ) const + { + m_Mutex.Lock(); + const unsigned int weakCount = OneOwnerRefCountInfo::HasWeakPointer(); + m_Mutex.Unlock(); + return weakCount; + } + + inline bool HasWeakPointer( void ) const + { + m_Mutex.Lock(); + const bool has = OneOwnerRefCountInfo::HasWeakPointer(); + m_Mutex.Unlock(); + return has; + } + + inline void IncWeakCount( void ) + { + m_Mutex.Lock(); + OneOwnerRefCountInfo::IncWeakCount(); + m_Mutex.Unlock(); + } + + inline void DecWeakCount( void ) + { + m_Mutex.Lock(); + OneOwnerRefCountInfo::DecWeakCount(); + m_Mutex.Unlock(); + } + + inline void ZapPointer( void ) + { + m_Mutex.Lock(); + OneOwnerRefCountInfo::ZapPointer(); + m_Mutex.Unlock(); + } + + void SetPointer( void * p ) + { + m_Mutex.Lock(); + OneOwnerRefCountInfo::SetPointer( p ); + m_Mutex.Unlock(); + } + + inline void * GetPointer( void ) const + { + return OneOwnerRefCountInfo::GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return OneOwnerRefCountInfo::GetPointerRef(); + } + +private: + /// Default constructor is not available. + Lockable1OwnerRefCountInfo( void ); + /// Copy constructor is not available. + Lockable1OwnerRefCountInfo( const Lockable1OwnerRefCountInfo & ); + /// Copy-assignment operator is not available. + Lockable1OwnerRefCountInfo & operator = ( const Lockable1OwnerRefCountInfo & ); + + mutable LOKI_DEFAULT_MUTEX m_Mutex; +}; + #endif // if object-level-locking or class-level-locking } // end namespace Private @@ -582,7 +871,7 @@ protected: return Decrement( strong ); } - bool HasStrongPointer( void ) const + inline bool HasStrongPointer( void ) const { return m_counts->HasStrongPointer(); } @@ -607,7 +896,12 @@ protected: } private: + + /// Default constructor is not implemented. TwoRefCounts( void ); + /// Copy constructor is not implemented. + TwoRefCounts( const TwoRefCounts & ); + /// Copy-assignment operator is not implemented. TwoRefCounts & operator = ( const TwoRefCounts & ); void Increment( bool strong ); @@ -618,6 +912,93 @@ private: Loki::Private::TwoRefCountInfo * m_counts; }; +//////////////////////////////////////////////////////////////////////////////// +/// \class SingleOwnerRefCount +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy extends the ownership +/// policy class, TwoRefCounts, to enforce that only one StrongPtr may "own" a +/// resource. The resource is destroyed only when its sole owner dies even if +/// weak pointers access it. The constructors enforce the single-owner policy +/// by throwing a bad_logic exception if more than one strong pointer claims to +/// own the resource. Use this policy when you want the code to specify that +/// only one object owns a resource. +/// +/// \note This class is not designed for use with a multi-threaded model. +/// Tests using a multi-threaded model may not run properly. +/// +/// \note If you use any single-owner class, you should also use the +/// OnlyStrongMayReset class for the ResetPolicy in StrongPtr. +/// +/// \note All single-owner policies do not allow programmers to return a +/// a StrongPtr by value from a function, since that would temporarily create +/// an additional strong co-pointer. Nor can programmers store any strong +/// co-pointers in a container that uses copy-in and copy-out semantics. Once +/// C++ allows for move constructors, these limitations go away. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT SingleOwnerRefCount +{ +protected: + + explicit SingleOwnerRefCount( bool strong ); + + SingleOwnerRefCount( const void * p, bool strong ); + + SingleOwnerRefCount( const SingleOwnerRefCount & rhs, + bool strong ); + + SingleOwnerRefCount( const SingleOwnerRefCount & rhs, + bool isNull, bool strong ); + + /** The destructor should not anything since the call to ZapPointer inside + StrongPtr::~StrongPtr will do the cleanup which this dtor would have done. + By the time the dtor is called, the underlying pointer, m_info, is NULL. + */ + inline ~SingleOwnerRefCount( void ) {} + + bool Release( bool strong ); + + inline bool HasStrongPointer( void ) const + { + return ( NULL != m_info->GetStrongCoPointer() ); + } + + void Swap( SingleOwnerRefCount & rhs ); + + void SetPointer( void * p ); + + void ZapPointer( void ); + + inline void * GetPointer( void ) const + { + return m_info->GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return m_info->GetPointerRef(); + } + +private: + /// Default constructor is not implemented. + SingleOwnerRefCount( void ); + /// Copy constructor is not implemented. + SingleOwnerRefCount( const SingleOwnerRefCount & ); + /// Copy-assignment operator is not implemented. + SingleOwnerRefCount & operator = ( const SingleOwnerRefCount & ); + + inline bool IsStrong( void ) const + { + return ( this == m_info->GetStrongCoPointer() ); + } + + ::Loki::Private::OneOwnerRefCountInfo * m_info; + +}; + +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + //////////////////////////////////////////////////////////////////////////////// /// \class LockableTwoRefCounts /// @@ -633,8 +1014,6 @@ private: /// do run properly. //////////////////////////////////////////////////////////////////////////////// -#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) - class LOKI_EXPORT LockableTwoRefCounts { typedef SmallValueObject< ::Loki::ClassLevelLockable > ThreadSafePointerAllocator; @@ -744,7 +1123,7 @@ protected: void Swap( LockableTwoRefCounts & rhs ) { - std::swap( m_counts, rhs.m_counts ); + ::std::swap( m_counts, rhs.m_counts ); } void SetPointer( void * p ) @@ -780,13 +1159,250 @@ protected: } private: + /// Default constructor is not implemented. LockableTwoRefCounts( void ); + /// Copy constructor is not implemented. + LockableTwoRefCounts( const LockableTwoRefCounts & ); + /// Copy-assignment operator is not implemented. LockableTwoRefCounts & operator = ( const LockableTwoRefCounts & ); /// Pointer to all shared data. Loki::Private::LockableTwoRefCountInfo * m_counts; }; +//////////////////////////////////////////////////////////////////////////////// +/// \class Lockable1OwnerRefCount +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy extends the ownership +/// policy class, LockableTwoRefCounts, to enforce that only one StrongPtr +/// may "own" a resource. The resource is destroyed only when its sole owner +/// dies regardless of how many weak pointers access it. The constructors +/// enforce the single-owner policy by throwing a bad_logic exception if more +/// than one strong pointer claims to own the resource. Use this policy when +/// you want the code to specify that only one object owns a resource. +/// +/// \note This class is not designed for use with a single-threaded model. +/// Tests using a single-threaded model will not run properly, but tests in a +/// multi-threaded model with either class-level-locking or object-level-locking +/// do run properly. +/// +/// \note If you use any single-owner class, you should also use the +/// OnlyStrongMayReset class for the ResetPolicy in StrongPtr. +/// +/// \note All single-owner policies do not allow programmers to return a +/// a StrongPtr by value from a function, since that would temporarily create +/// an additional strong co-pointer. Nor can programmers store any strong +/// co-pointers in a container that uses copy-in and copy-out semantics. Once +/// C++ allows for move constructors, these limitations go away. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT Lockable1OwnerRefCount +{ + typedef SmallValueObject< ::Loki::ClassLevelLockable > ThreadSafePointerAllocator; + +protected: + + explicit Lockable1OwnerRefCount( bool strong ) + : m_info( NULL ) + { + assert( NULL != this ); + + void * temp = SmallObject<>::operator new( + sizeof(Loki::Private::Lockable1OwnerRefCountInfo) ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( temp != 0 ); +#endif + + Lockable1OwnerRefCount * ptr = ( strong ) ? this : NULL; + m_info = new ( temp ) + ::Loki::Private::Lockable1OwnerRefCountInfo( ptr ); + } + + Lockable1OwnerRefCount( const void * p, bool strong ) + : m_info( NULL ) + { + assert( NULL != this ); + + void * temp = SmallObject<>::operator new( + sizeof(Loki::Private::Lockable1OwnerRefCountInfo) ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( temp != 0 ); +#endif + + Lockable1OwnerRefCount * ptr = ( strong ) ? this : NULL; + m_info = new ( temp ) + ::Loki::Private::Lockable1OwnerRefCountInfo( p, ptr ); + } + + Lockable1OwnerRefCount( const Lockable1OwnerRefCount & rhs, bool strong ) : + m_info( rhs.m_info ) + { + assert( NULL != this ); + + if ( strong && rhs.HasStrongPointer() ) + { + throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message ); + } + + m_info = rhs.m_info; + if ( strong ) + { + m_info->SetStrongCoPtr( this ); + } + else + { + m_info->IncWeakCount(); + } + } + + Lockable1OwnerRefCount( const Lockable1OwnerRefCount & rhs, + bool isNull, bool strong ) : + m_info( ( isNull ) ? NULL : rhs.m_info ) + { + assert( NULL != this ); + + if ( isNull ) + { + void * temp = SmallObject<>::operator new( + sizeof(Loki::Private::Lockable1OwnerRefCountInfo) ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( temp != 0 ); +#endif + + Lockable1OwnerRefCount * ptr = ( strong ) ? this : NULL; + m_info = new ( temp ) + ::Loki::Private::Lockable1OwnerRefCountInfo( ptr ); + return; + } + + if ( strong && rhs.HasStrongPointer() ) + { + throw ::std::logic_error( StrongPtr_Single_Owner_Exception_Message ); + } + + m_info = rhs.m_info; + if ( strong ) + { + m_info->SetStrongCoPtr( this ); + } + else + { + m_info->IncWeakCount(); + } + } + + /** The destructor does not need to do anything since the call to + ZapPointer inside StrongPtr::~StrongPtr will do the cleanup which + this dtor would have done. + */ + inline ~Lockable1OwnerRefCount( void ) {} + + inline void Lock( void ) const + { + m_info->Lock(); + } + + inline void Unlock( void ) const + { + m_info->Unlock(); + } + + inline bool Release( bool strong ) + { + assert( NULL != this ); + assert( strong == IsStrong() ); + + if ( strong ) + { + m_info->SetStrongCoPtr( NULL ); + return true; + } + + m_info->Lock(); + assert( 0 < m_info->GetWeakCount() ); + m_info->DecWeakCount(); + const bool noOwner = ( !m_info->HasStrongPointer() ); + const bool doRelease = ( ( 0 == m_info->GetWeakCount() ) && noOwner ); + m_info->Unlock(); + return doRelease; + } + + bool HasStrongPointer( void ) const + { + return m_info->HasStrongPointer(); + } + + void Swap( Lockable1OwnerRefCount & rhs ) + { + assert( NULL != this ); + m_info->Lock(); + rhs.m_info->Lock(); + + if ( IsStrong() && rhs.IsStrong() ) + { + // These two strong pointers are trading resources. + rhs.m_info->SetStrongCoPtr( this ); + m_info->SetStrongCoPtr( &rhs ); + } + ::std::swap( m_info, rhs.m_info ); + m_info->Unlock(); + rhs.m_info->Unlock(); + } + + void SetPointer( void * p ) + { + assert( NULL != this ); + if ( IsStrong() || ( 1 == m_info->GetWeakCount() ) ) + { + // Only a strong pointer or the last weak pointer may change a resource. + m_info->SetPointer( p ); + } + } + + void ZapPointer( void ) + { + assert( !m_info->HasStrongPointer() ); + if ( m_info->HasWeakPointer() ) + { + m_info->ZapPointer(); + } + else + { + SmallObject<>::operator delete ( m_info, + sizeof(Loki::Private::Lockable1OwnerRefCountInfo) ); + m_info = NULL; + } + } + + inline void * GetPointer( void ) const + { + return m_info->GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return m_info->GetPointerRef(); + } + +private: + /// Default constructor is not implemented. + Lockable1OwnerRefCount( void ); + /// Copy constructor is not implemented. + Lockable1OwnerRefCount( const Lockable1OwnerRefCount & ); + /// Copy-assignment operator is not implemented. + Lockable1OwnerRefCount & operator = ( const Lockable1OwnerRefCount & ); + + inline bool IsStrong( void ) const + { + return ( this == m_info->GetStrongCoPointer() ); + } + + /// Pointer to shared info about resource. + ::Loki::Private::Lockable1OwnerRefCountInfo * m_info; + +}; + #endif // if object-level-locking or class-level-locking //////////////////////////////////////////////////////////////////////////////// @@ -817,14 +1433,21 @@ protected: TwoRefLinks( const TwoRefLinks & rhs, bool isNull, bool strong ); + ~TwoRefLinks( void ); + bool Release( bool strong ); void Swap( TwoRefLinks & rhs ); bool Merge( TwoRefLinks & rhs ); + /// Returns pointer to next link in cycle is a strong pointer. + const TwoRefLinks * GetNextStrongPointer( void ) const; + bool HasStrongPointer( void ) const; + unsigned int GetStrongPointerCount( void ) const; + inline void ZapPointer( void ) { ZapAllNodes(); @@ -842,13 +1465,20 @@ protected: return const_cast< void * & >( m_pointer ); } + inline bool IsStrong( void ) const + { + return m_strong; + } + private: static unsigned int CountPrevCycle( const TwoRefLinks * pThis ); static unsigned int CountNextCycle( const TwoRefLinks * pThis ); - /// Not implemented. + /// Default constructor is not implemented. TwoRefLinks( void ); - /// Not implemented. + /// Copy constructor is not implemented. + TwoRefLinks( const TwoRefLinks & ); + /// Copy-assignment operator is not implemented. TwoRefLinks & operator = ( const TwoRefLinks & ); bool HasPrevNode( const TwoRefLinks * p ) const; @@ -856,12 +1486,69 @@ private: bool AllNodesHaveSamePointer( void ) const; void ZapAllNodes( void ); + bool IsValid( void ) const; + void * m_pointer; mutable TwoRefLinks * m_prev; mutable TwoRefLinks * m_next; const bool m_strong; }; +//////////////////////////////////////////////////////////////////////////////// +/// \class SingleOwnerRefLinks +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy extends the ownership +/// policy class, TwoRefLinks, to enforce that only one StrongPtr may "own" a +/// resource. The resource is destroyed only when its sole owner dies even if +/// weak pointers access it. The constructors enforce the single-owner policy +/// by throwing a bad_logic exception if more than one strong pointer claims to +/// own the resource. Use this policy when you want the code to specify that +/// only one object owns a resource. +/// +/// \note This class is not designed for use with a multi-threaded model. +/// Tests using a multi-threaded model may not run properly. +/// +/// \note If you use any single-owner class, you should also use the +/// OnlyStrongMayReset class for the ResetPolicy in StrongPtr. +/// +/// \note All single-owner policies do not allow programmers to return a +/// a StrongPtr by value from a function, since that would temporarily create +/// an additional strong co-pointer. Nor can programmers store any strong +/// co-pointers in a container that uses copy-in and copy-out semantics. Once +/// C++ allows for move constructors, these limitations go away. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT SingleOwnerRefLinks : public TwoRefLinks +{ +protected: + + explicit SingleOwnerRefLinks( bool strong ); + + SingleOwnerRefLinks( const void * p, bool strong ); + + SingleOwnerRefLinks( const SingleOwnerRefLinks & rhs, bool strong ); + + SingleOwnerRefLinks( const SingleOwnerRefLinks & rhs, bool isNull, bool strong ); + + ~SingleOwnerRefLinks( void ); + + void Swap( SingleOwnerRefLinks & rhs ); + + bool Merge( SingleOwnerRefLinks & rhs ); + + bool Release( bool strong ); + +private: + + /// Default constructor is not implemented. + SingleOwnerRefLinks( void ); + /// Copy constructor is not implemented. + SingleOwnerRefLinks( const SingleOwnerRefLinks & ); + /// Copy-assignment operator is not implemented. + SingleOwnerRefLinks & operator = ( const SingleOwnerRefLinks & ); +}; + //////////////////////////////////////////////////////////////////////////////// /// \class StrongPtr /// @@ -880,11 +1567,11 @@ template < typename T, bool Strong = true, - class OwnershipPolicy = Loki::TwoRefCounts, - class ConversionPolicy = Loki::DisallowConversion, - template < class > class CheckingPolicy = Loki::AssertCheck, - template < class > class ResetPolicy = Loki::CantResetWithStrong, - template < class > class DeletePolicy = Loki::DeleteSingle, + class OwnershipPolicy = ::Loki::TwoRefCounts, + class ConversionPolicy = ::Loki::DisallowConversion, + template < class > class CheckingPolicy = ::Loki::AssertCheck, + template < class > class ResetPolicy = ::Loki::CantResetWithStrong, + template < class > class DeletePolicy = ::Loki::DeleteSingle, template < class > class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS > class StrongPtr @@ -1072,7 +1759,7 @@ public: return *this; } - bool IsStrong( void ) const + inline bool IsStrong( void ) const { return Strong; } @@ -1159,7 +1846,7 @@ public: friend bool ReleaseAll( StrongPtr & sp, typename StrongPtr::StoredType & p ) { - if ( !sp.RP::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + if ( !sp.RP::OnReleaseAll( sp.IsStrong(), sp.OP::HasStrongPointer() ) ) { return false; } @@ -1175,7 +1862,7 @@ public: { return true; } - if ( !sp.RP::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + if ( !sp.RP::OnResetAll( sp.IsStrong(), sp.OP::HasStrongPointer() ) ) { return false; } @@ -1498,7 +2185,7 @@ template bool ReleaseAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp, typename StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >::StoredType & p ) { - if ( !sp.RP::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + if ( !sp.RP::OnReleaseAll( sp.IsStrong(), sp.OP::HasStrongPointer() ) ) { return false; } @@ -1526,7 +2213,7 @@ bool ResetAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp, { return true; } - if ( !sp.RP::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + if ( !sp.RP::OnResetAll( sp.IsStrong(), sp.OP::HasStrongPointer() ) ) { return false; }