1

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

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

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

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

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

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

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

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

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

干杯,谢恩

4

4 回答 4

6

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

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

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

于 2011-07-28T07:40:13.220 回答
3

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

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

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

stl/boost 中是否已经有这样的指针/模式,我错过了,还是我应该自己滚动?

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

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

于 2011-07-28T07:41:48.180 回答
1

我不确定弱指针会有多大帮助。通常,如果一个组件 X 使用另一个组件 Y,X 必须被告知 Y 的消亡,不仅是为了使指针无效,而且可能是将它从列表中删除,或者改变它的操作模式以便它不再需要该对象. 许多年前,当我第一次开始使用 C++ 时,有一系列活动试图找到一个好的通用解决方案。(这个问题当时被称为关系管理。)据我所知,没有找到好的通用解决方案。至少,我从事的每个项目都使用了基于观察者模式的手工构建解决方案。

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

于 2011-07-28T08:01:00.510 回答
0

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

于 2011-07-28T08:15:36.650 回答