我最近遇到了一个问题,即unique_ptrshared_ptr都不是正确的解决方案。
因此,我正在考虑发明另一种智能ptr(如下所述),但我心想:“我当然不是第一个想要这种东西的人。”

所以我的高级问题是:

  • 以下设计有意义吗?
  • 是否可以使用现有的智能ptrs(或其他std::功能)来完成此操作,也许我遗漏了一些东西?


  • 要求:
  • 我想要单一所有权,就像unique_ptr
  • 也就是说:仅当单个拥有者指针死亡时,才应释放基础对象(与shared_ptr的行为不同)。
  • 我想要一些其他方法来引用删除对象时“知道”的对象。因此,类似于weak_ptr,但要与单个所有权模型一起使用。
  • 我不需要线程安全

  • 激励示例:

    假设我要遍历接口(interface)指针的列表,并在其上调用方法。
    这些方法中的某些方法可能导致列表中后面的项目被删除。

    使用普通指针,我将获得那些已删除项目的悬挂引用。

    建议设计:

    让我们将所有者指针my_ptr和非所有者引用my_weak_ptr称为。

    对于一个给定的对象,我们可能有一个像这样的图:
                                 _______
    my_ptr<Obj> owner ---------> |Obj* | -------> [Obj data ... ]
                          +----> |count|
                          | +--> |_____|
    my_weak_ptr<Obj> A ---+ |
                            |
    my_weak_ptr<Obj> B -----+
    
    my_ptr将具有与unique_ptr大致相同的接口(interface)。
    在内部,它将存储指向“控制块”的指针,该指针实际上只是“真实”指针和控制块本身的引用计数。
    销毁后,my_ptr会将控制块指针设置为NULL并减少引用计数(并在适当时删除控制块)。
    my_weak_ptr将是可复制的,并且具有一些get()方法,该方法将返回真正的Obj*
    用户将负责在使用它之前检查它是否为NULL。
    销毁时,my_weak_ptr将减少计数(并在适当的情况下删除控制块)。

    缺点是每次访问都会在内存中进行两次跳跃。
    对于my_ptr,也可以通过在内部存储真实的Obj*来减轻这种情况,但是my_weak_ptr引用将始终必须支付该双跳费用。

    编辑:一些相关的问题,来自给定的链接:
  • Non-ownership copies of std::unique_ptr
  • Is it possible / desirable to create non-copyable shared pointer analogue (to enable weak_ptr tracking / borrow-type semantics)?
  • Better shared_ptr by distinct types for "ownership" and "reference"?

  • 因此,似乎需要这样的东西,但没有灌篮解决方案。如果需要线程安全,则shared_ptrweak_ptr是正确的选择,但如果不是,它们会增加不必要的开销。

    还有 boost::local_scoped_ptr ,但是它仍然是一个共享所有权模型。我宁愿阻止拥有指针的拷贝,例如unique_ptr

    最佳答案

    上面的评论中进行了很好的讨论,因此我将尝试回答我自己的问题并进行总结:
    首先,整个概念有一个整体缺点:my_weak_ptr的任何用户都必须非常小心,不要调用某些可能导致底层对象被删除的函数。否则,他们需要重新检查弱ptr的无效性。这是对用户施加的非强制(和不可强制)约束,就像他们使用原始指针一样。
    话虽这么说:这不是新领域。在随后的研究中,我发现了这种想法的各种化身:

  • VISH StrongPtr/WeakPtr
  • 非常合适。请注意,WeakPtr没有lock()方法,并且文档说:“如果所引用的对象从其他地方被破坏,则弱指针会神奇地变为null”。
  • 但是,它仍然是可复制的,因此不表示唯一所有权。

  • Loki StrongPtr
  • 通过适本地使用令人眼花policies乱的策略选择(或者可能是自定义的策略),我认为可以实现我所描述的内容。

  • trackable_ptr
  • 一种不同的方法,因为您的T必须包装为trackable<T>,但是类似的问题正在解决。


  • 还有一些接近std的“相当不错,但不是很理想”的解决方案:
  • 使用shared_ptrweak_ptr
  • 缺点:线程安全开销,可复制的所有者ptr,多个引用计数。

  • boost::local_shared_ptr,与weak_ptr兼容。
  • 缺点:可复制的所有者ptr,多个引用计数。

  • local_shared_ptr可能是最好的即用型解决方案,它具有高品质且几乎没有缺点。
    但是,要真正挤出最后几个字节并禁止复制,将需要自定义解决方案。
    另外,从哲学上讲:
    从这里的讨论和其他阅读中,我认为很多人都相信对所有权的二进制方法:要么是共享的(所以使用shared_ptr,它也可以通过weak_ptr提供共享的观察),或者它是唯一的(所以请使用unique_ptr) 。
    这大概涵盖了90%以上的案例。但是我希望拥有共享观察权的唯一所有权(这是我的措辞;根据您的语义,您可以使用不同的词)。该标准可能无法满足要求,但对于资源受限的系统,我认为这似乎是一个合理的利基市场。

    09-07 06:26