|
From: <ric...@us...> - 2010-10-30 03:09:32
|
Revision: 1079
http://loki-lib.svn.sourceforge.net/loki-lib/?rev=1079&view=rev
Author: rich_sposato
Date: 2010-10-30 03:09:25 +0000 (Sat, 30 Oct 2010)
Log Message:
-----------
Added 3 new policy classes to support single-owner smart
pointers. Changed how ResetPolicy classes get called.
Modified Paths:
--------------
trunk/include/loki/StrongPtr.h
Modified: trunk/include/loki/StrongPtr.h
===================================================================
--- trunk/include/loki/StrongPtr.h 2010-09-16 17:32:24 UTC (rev 1078)
+++ trunk/include/loki/StrongPtr.h 2010-10-30 03:09:25 UTC (rev 1079)
@@ -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,7 +118,10 @@
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,18 +253,45 @@
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;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
/// \class AllowReset
///
/// \ingroup StrongPointerResetGroup
@@ -272,12 +302,16 @@
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 @@
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 @@
}
private:
+ /// Default constructor not implemented.
+ TwoRefCountInfo( void );
/// Copy-constructor not implemented.
TwoRefCountInfo( const TwoRefCountInfo & );
/// Copy-assignment operator not implemented.
@@ -410,6 +454,105 @@
};
////////////////////////////////////////////////////////////////////////////////
+/// \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
///
/// \ingroup StrongPointerOwnershipGroup
@@ -427,8 +570,6 @@
/// 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 @@
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 @@
return Decrement( strong );
}
- bool HasStrongPointer( void ) const
+ inline bool HasStrongPointer( void ) const
{
return m_counts->HasStrongPointer();
}
@@ -607,7 +896,12 @@
}
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 );
@@ -619,6 +913,93 @@
};
////////////////////////////////////////////////////////////////////////////////
+/// \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
///
/// \ingroup StrongPointerOwnershipGroup
@@ -633,8 +1014,6 @@
/// 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 @@
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 @@
}
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 @@
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 @@
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,6 +1486,8 @@
bool AllNodesHaveSamePointer( void ) const;
void ZapAllNodes( void );
+ bool IsValid( void ) const;
+
void * m_pointer;
mutable TwoRefLinks * m_prev;
mutable TwoRefLinks * m_next;
@@ -863,6 +1495,61 @@
};
////////////////////////////////////////////////////////////////////////////////
+/// \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
///
/// \ingroup SmartPointerGroup
@@ -880,11 +1567,11 @@
<
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 @@
return *this;
}
- bool IsStrong( void ) const
+ inline bool IsStrong( void ) const
{
return Strong;
}
@@ -1159,7 +1846,7 @@
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 @@
{
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 @@
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<T>::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) )
+ if ( !sp.RP<T>::OnReleaseAll( sp.IsStrong(), sp.OP::HasStrongPointer() ) )
{
return false;
}
@@ -1526,7 +2213,7 @@
{
return true;
}
- if ( !sp.RP<T>::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) )
+ if ( !sp.RP<T>::OnResetAll( sp.IsStrong(), sp.OP::HasStrongPointer() ) )
{
return false;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|