【问题标题】:Is there a boost::weak_intrusive_pointer?是否有 boost::weak_intrusive_pointer?
【发布时间】:2011-01-24 22:05:44
【问题描述】:

出于遗留原因,我需要使用侵入式指针,因为我需要能够将原始指针转换为智能指针。

但是我注意到没有用于提升的弱侵入性指针。我确实在 boost 线程列表中找到了有关它的讨论,但没有具体内容。

有人知道弱侵入指针的线程安全实现吗?

谢谢 丰富

【问题讨论】:

    标签: c++ boost pointers weak


    【解决方案1】:

    这没有任何意义。

    详细说明:weak_ptr 指向 counter 对象的同一实例 shared_ptr 所做的。当shared_ptr 超出范围时,counter 的实例将保留(有效计数为 0),这允许weak_ptr 实例检查它们是否有效地指向一个已释放的对象。

    使用侵入式计数,计数器集成在对象中。当计数达到 0 时,该对象通常要么被回收要么被删除......但关键是计数器不再可用。理由是这样可以实现更高效的存储(1 个单块)和更快的速度(缓存局部性)。

    如果您需要弱引用计数并且不关心侵入式计数的好处,您可以使用shared_ptrweak_ptr 的组合。

    这个想法是解除计数器与对象的关联。

    class Counted
    {
      // bla
    private:
      boost::shared_ptr<int> mCounter;
    };
    

    现在你可以返回弱句柄了:

    class WeakHandle
    {
    public:
      explicit WeakHandle(Counted& c): mCounter(c.mCounter), mObject(&c) {}
    
      bool expired() const { return mCounter.expired(); }
    
    private:
      boost::weak_ptr<int> mCounter;
      Counted* mObject;
    };
    

    在这里,我们将计数器的生命周期与对象的生命周期解除关联,以便它能够在对象的破坏中幸存下来……部分。从而使weak_ptr 成为可能。

    当然,使用shared_ptrweak_ptr 这是线程安全的;)

    【讨论】:

    • 我的想法是将共享 ptr 和弱 ptr 使用的共享对象嵌入到宿主对象中,并且 intrusive_weak_ptr (如果存在)将使用与 weak_ptr 相同的方式使用它。当没有更多引用时,我仍然需要删除对象的功能。另外我需要采取弱引用。
    • 我想你没有理解我的意思:这正是我的建议。 Counted 对象是“侵入式”计数的,我只是将计数器从普通整数更改为指向整数的指针。至于你的intrusive_weak_ptr,就是我所说的WeakHandle
    • 啊,我想我和你在一起。所以我会像往常一样使用侵入式指针,但是当调用 intrusive_ptr_add_ref 时,我会从共享指针中引用 int 作为我的计数。当它达到零时,对象被释放,但是任何弱引用都维护一个指向 int 的指针。对吗?
    • 我不认为WeakHandleweak_ptr 一样是线程安全的。 WeakHandle 仅保存一个原始指针,它不会使 Counted 保持活动状态。 OTOH,锁定 weak_ptr 会产生 shared_ptr,因此在线程访问指针时无法删除指针。
    【解决方案2】:

    我不太喜欢前面的任何一个答案,所以:

    不,我不知道有什么实现,但我认为这是可能的。 shared_ptr 的标准实现包含两个引用计数,一个用于“强”引用,一个用于“弱”引用,以及一个指向所指对象的指针。在 intrusive_ptr 实现中,强计数必须是对象的一部分,但弱计数不能。因此,您似乎可以创建一个“弱” intrusive_ptr。

    定义一个弱指针助手:

    template<class X>
    class intrusive_ptr_weak_helper {
        long weak_ref_count;
        X *target_instance;
    };
    

    然后将其记录到引用计数旁边的对象中:

    struct X {
        ...
        intrusive_ptr_weak_helper *ref_weak_helper;
        ...
        long ref_count;
        ...
    };
    

    构造X时:

    ref_count = 0;
    ref_weak_helper = NULL;
    

    “强”指针 intrusive_strong_ptr 与 intrusive_ptr 相同,直到发生删除。当强引用计数变为零时(在删除发生之前):

    if (ref_weak_helper != NULL) {
        if (ref_weak_helper->weak_ref_count == 0)
            delete ref_weak_helper;
        else
            ref_weak_helper->target_instance = NULL;
    }
    

    “弱”版本,intrusive_weak_ptr,记录指向弱助手的指针,操纵引用计数,并通过 target_instance 指针访问目标对象。当weak_ref_count 减为零时,target_instance 的状态决定了助手是否被删除。

    缺少许多细节(例如并发问题),但这是 shared_ptr 和 intrusive_ptr 的混合。它保持了 intrusive_ptr 的基本优点(缓存优化、重用 3rd 方侵入(强)引用计数、强和弱指针替代是指针大小的),同时主要在弱引用路径中增加了额外的工作。

    【讨论】:

      【解决方案3】:

      侵入式指针的当前实现是使用引用计数器。所以删除对象delete也会删除计数器,所以weak_intrusive_pointer永远不会知道对象被删除了。

      如果你需要从this获取weak_ptr,你可能搜索boost::enable_shared_from_this&lt;T&gt;

      【讨论】:

        【解决方案4】:

        OpenSceneGraph 及其后继者 VulkanSceneGraph 都具有侵入式强指针和关联弱指针的全面实现,分别命名为 ref_ptr 和 observer_ptr。

        我不知道这些系统的每一个细节,但它们似乎使用了一个额外的对象,当引用对象(引用类的后代)被删除时,该对象会得到通知。当尝试将弱指针转换为强指针时,弱指针会使用这第三个对象。

        VulkanSceneGraph 是目前正在开发的下一代场景图,旨在取代 OpenSceneGraph,因此我认为它的侵入式指针系统是一种更高级的实现。

        值得一试:

        https://github.com/vsg-dev/VulkanSceneGraph/blob/master/include/vsg/core/observer_ptr.h

        【讨论】:

        • 这里的弱指针是使用一个有点重的对象实现的,称为辅助(包含看起来像一些用于浮动弱引用的调试助手)。看起来它正在解决一些额外的问题,而不仅仅是弱侵入性指针,但总的来说看起来像是我在评论中描述的实现
        猜你喜欢
        • 1970-01-01
        • 2011-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多