Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing weak intrusive pointers in C++

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()?

like image 586
Sergey K. Avatar asked Nov 12 '12 12:11

Sergey K.


1 Answers

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.

like image 67
armel Avatar answered Oct 11 '22 00:10

armel