Реализация слабых интрузивных указателей в С++

Слабые указатели похожи на интеллектуальные указатели, за исключением того, что ссылки от слабых указатели не предотвращают сбор мусора, а слабые указатели должны проверяют их действительность до их использования.

В нашем проекте (Linderdaum Engine http://www.linderdaum.com) мы используем интрузивные указатели. Чтобы избежать круговых ссылок и островов изоляции, мы реализовали слабые интрузивные указатели следующим образом:

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 здесь только для форвардных объявлений и делает примерно следующее:

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 является глобальным в области sEnvironment и при каждом создании нового объекта создается атомарным приращением.

Мои вопросы:

1) Безопасно ли реализовать такие слабые ссылки?

2) Существуют ли способы оптимизации clWeakPtr::Lock()?

Ответ 1

1) Это действительно безопасно, но любая модификация графика будет иметь некоторое противоречие с LPtr::GetObjectsGraphPtrWrapper

2) блокировка чтения-записи может помочь, по крайней мере, вы сможете несколько раз вызвать несколько Lock()

Проблема с вашим решением заключается в том, что он побеждает местность, которую приносят неинтрузивные слабые указатели. В зависимости от уровня concurrency это может стать проблемой, поскольку каждый вызов Lock() предотвратит создание какого-либо объекта, а также любой другой вызов Lock() без блокировки чтения-записи.