【问题标题】:Implementing weak intrusive pointers in C++在 C++ 中实现弱侵入式指针
【发布时间】:2012-11-12 12:12:18
【问题描述】:

弱指针类似于智能指针,只是来自弱指针的引用 指针不会阻止垃圾收集,弱指针必须 在使用之前检查其有效性。

在我们的项目(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>();

GenerationsEnvironment 的范围内是全局的,并且每次实例化一个新对象时都会以原子方式递增。

我的问题是:

1) 像这样实现弱引用是否安全?

2) 有没有办法优化clWeakPtr::Lock()

【问题讨论】:

    标签: c++ smart-pointers weak-references


    【解决方案1】:

    1) 看起来确实很安全,但是对图表的任何修改都会与LPtr::GetObjectsGraphPtrWrapper 发生争用

    2) 读写锁可能会有所帮助,至少您可以并行调用多个Lock()

    您的解决方案的问题在于它破坏了非侵入式弱指针带来的局部性。 根据并发级别,这可能会成为一个问题,因为每次调用 Lock() 都会阻止任何对象的创建,以及任何其他没有读写锁的 Lock() 调用。

    【讨论】:

    • 如果您可以访问 boost,您可以使用 boost::shared_mutex(如stackoverflow.com/questions/244316/reader-writer-locks-in-c,那里也有针对 Windows 的响应),对于 pthreads (stackoverflow.com/questions/8635963/…),您的 LPtr: :GetObjectsGraphPtrWrapper 将是一个读取器,而实际修改图形的函数将是一个写入器。请注意,它只会保护图形和对象的存在,而不是对象的内容(除非您在修改对象之前进行写锁定,这取决于您的需要)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 2012-01-11
    相关资源
    最近更新 更多