【问题标题】:Weak reference to a scoped_ptr?对 scoped_ptr 的弱引用?
【发布时间】:2011-07-28 07:32:46
【问题描述】:

我通常遵循 Google 风格指南,我觉得这与我看待事物的方式非常吻合。我也几乎完全使用 boost::scoped_ptr 以便只有一个管理器拥有特定对象的所有权。然后我传递裸指针,我的想法是我的项目的结构使得所述对象的管理器总是在使用它们的对象被销毁后被销毁。

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Smart_Pointers

这一切都很好,但是我只是被一个令人讨厌的小内存踩踏错误咬住了,其中所有者恰好在使用它的对象被删除之前被删除。

现在,在每个人都认为我是这种模式的傻瓜之前,我为什么不直接使用 shared_ptr 呢?等等,考虑一下我不想有未定义的所有者语义这一点。尽管 shared_ptr 会捕捉到这种特殊情况,但它会向系统用户发送错误消息。它说,“我不知道这是谁的,可能是你!”

对我有帮助的是指向作用域指针的弱指针。实际上,一个具有弱引用列表的作用域指针,当作用域指针解构时,这些弱引用被清空。这将允许单一所有权语义,但让使用对象有机会发现我遇到的问题。

因此,以针对 scoped_ptr 的额外“weak_refs”指针和针对weak_ptr 中的“next_weak_ptr”的额外指针为代价,它会形成一个简洁的小型单所有者、多用户结构。

它甚至可能只是一个调试功能,所以在“发布”时,整个系统只是变回正常大小的 scoped_ptr 和弱引用的标准单指针。

所以......我的问题是:

  1. 在我的 stl/boost 中是否已经存在这样的指针/模式 错过了,还是我应该自己滚动?
  2. 有没有更好的方法,即 仍然满足我的单一所有权目标?

干杯, 谢恩

【问题讨论】:

  • 我不知道标准或库实现。如果你确实实现了你所描述的,你最终会得到一个与 boost shared_ptr/weak_ptr 非常相似的实现,因为你可能想要检测有人从weak_ptr 中获取原始指针并缓存它的情况。话虽如此,您可能只想使用 shared_ptr/weak_ptr 并在您的“管理器”中断言它保留的 shared_ptr 在您想要销毁对象时是唯一的。

标签: c++ structure weak-ptr scoped-ptr


【解决方案1】:

 2. 有没有更好的方法,仍然可以满足我的单一所有权目标?

请使用shared_ptr,但作为类成员,它是该类不变量的一部分,并且公共接口只公开了一种获取weak_ptr的方法。

当然,病态代码可以从weak_ptr 中保留自己的shared_ptr,只要他们愿意。我不建议在这里尝试保护马基雅维利,只保护墨菲(使用萨特的话)。另一方面,如果您的用例是异步的,那么锁定weak_ptr 返回shared_ptr 可能是一个特性!

【讨论】:

  • 这实际上是隐藏所有权问题的好方法。我喜欢它:)
【解决方案2】:

虽然 shared_ptr 会捕捉到这种特殊情况,但它会向系统用户发送错误消息。它说,“我不知道这是谁的,可能是你!”

shared_ptr 并不意味着“我不知道谁拥有这个”。这意味着“我们拥有这个。”仅仅因为一个实体没有独占所有权并不意味着任何人都可以拥有它。

shared_ptr 的目的是确保指针在共享它的每个人都同意应该销毁之前不会被销毁。

在我缺少的 stl/boost 中是否已经存在这样的指针/模式,或者我应该自己滚动?

您可以像使用 scoped_ptr 一样使用 shared_ptr。仅仅因为它可以共享并不意味着您必须共享它。那将是最简单的工作方式;让单一所有权成为一种约定,而不是 API 建立的规则。

但是,如果您需要一个单一所有者的指针但又具有弱指针,那么 Boost 中没有。

【讨论】:

  • 嗨 Nicol,是的,我在“我不知道谁拥有这个......”这句话中有点夸张,但是是的,你是对的 ;) 至于你的观点,我是开始重新思考我实施单一所有权的做法,并且只是使用 shared_ptr 方法。
【解决方案3】:

我不确定弱指针会有多大帮助。通常,如果一个 组件 X 使用另一个组件 Y,X 必须被告知 Y 的死亡, 不仅要使指针无效,还可以将其从列表中删除, 或改变其操作模式,使其不再需要 目的。许多年前,当我第一次接触 C++ 时, 试图找到一个好的通用解决方案的活动。 (问题是 当时叫关系管理。)据我所知,不好 找到了通用解决方案;至少,我参与的每个项目 使用了基于观察者模式的手工构建解决方案。

我的网站上确实有一个ManagedPtr,当时它还在运行,它的行为 和你描述的差不多。在实践中,除了特定的 导致它的案例,我从未找到它的真正用途,因为 总是需要通知。但是,实施起来并不难。 托管对象派生自 ManagedObject 类,并获取所有 它发出的指针(ManagedPtr,而不是原始指针)。 指针本身注册到ManagedObject 类,并且 ManagedObject 类的析构函数访问它们,并“断开连接” 他们通过将实际指针设置为空。当然,ManagedPtr 有一个isValid 函数,以便客户端代码可以在之前测试 取消引用。这很好用(无论对象如何 托管——我的大多数实体对象“拥有”自己,并执行 delete this 是对某些特定输入的响应),除了你倾向于 泄漏无效的ManagedPtr(例如,每当客户端保留指针时 在某种容器中,因为它可能有多个),以及 如果客户需要采取一些行动,他们仍然不会收到通知 对象死亡。

【讨论】:

  • 嗨,詹姆斯,我已经实现了一个类似的容器,之前它在调用像“objectDeleting”函数这样的函数后有效地将所有引用/指针归零。它实际上只是观察者模式。我开始认为我的经理案也没有必要。
【解决方案4】:

如果你碰巧在使用 QT,QPointer 基本上是一个指向QObject 的弱指针。它将自己连接到指向值中的“我刚刚被破坏”事件,并根据需要自动使自己无效。但是,如果您还没有跳过 QT 的圈子,那么这是一个非常庞大的库,可以用来进行错误跟踪。

【讨论】:

    猜你喜欢
    • 2011-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    • 2015-08-18
    相关资源
    最近更新 更多