Weak pointers are like smartpointers, except that references from weak
pointers do not prevent garbage collection, and weak pointers must
have their validity checked before they are used.
In our project (Linderdaum Engine http://www.linderdaum.com) we use intrusive pointers. To avoid circular references and islands of isolation we have implemented weak intrusive pointers the following way:
namespace LPtr
{
clPtr<iObject> GetObjectsGraphPtrWrapper( sEnvironment* Env, iObject* Obj, size_t Generation );
};
/// Intrusive weak smart pointer
template <class T> class clWeakPtr
{
public:
/// default constructor
clWeakPtr(): Env( NULL ), FObject( NULL ), FGeneration( 0 ) {}
explicit clWeakPtr( T* Ptr )
: Env( Ptr ? Ptr->Env : NULL )
, FObject( Ptr )
, FGeneration( Ptr ? Ptr->FGeneration : 0 ) {}
explicit clWeakPtr( const clPtr<T>& Ptr )
: Env( Ptr ? Ptr->Env : NULL )
, FObject( Ptr.GetInternalPtr() )
, FGeneration( Ptr ? Ptr->FGeneration : 0 ) {}
clPtr<T> Lock() const
{
clPtr<iObject> P = LPtr::GetObjectsGraphPtrWrapper( Env, FObject, FGeneration );
return P.DynamicCast<T>();
}
private:
sEnvironment* Env;
T* FObject;
size_t FGeneration;
};
GetObjectsGraphPtrWrapper is here just for the sake of forward declarations and does roughly this:
LMutex Lock( &FObjectsGraphMutex );
clObjectsGraph::const_iterator i = std::find( Env->ObjectsGraph.begin(), Env->ObjectsGraph.end(), Obj );
if ( i == Env->ObjectsGraph.end() ) return clPtr<iObject>();
bool IsSame = Obj->FGeneration == Generation;
bool IsAlive = Obj->GetReferenceCounter() > 0;
return ( IsSame && IsAlive ) ? clPtr<iObject>( Obj ) : clPtr<iObject>();
Generation is global in the scope of sEnvironment and is atomic-incremented every time a new object is instantiated.
My questions are:
1) Is it safe to implement weak-references like this?
2) Are there any ways to optimize the clWeakPtr::Lock()?
1) It seems safe indeed, but any modification of the graph will have some contention with
LPtr::GetObjectsGraphPtrWrapper2) a read-write lock could help, at least you’ll be able to call several
Lock()in parallelThe problem with your solution is that it defeats the locality that non-intrusive weak pointers bring.
Depending on the concurrency level, it might become a problem as each call to
Lock()will prevent any object creation and as well any otherLock()call without a read-write lock.