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::GetObjectsGraphPtrWrapper
2) a read-write lock could help, at least you'll be able to call several Lock()
in parallel
The 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 other Lock()
call without a read-write lock.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With