【问题标题】:Better shared_ptr by distinct types for "ownership" and "reference"?通过“所有权”和“参考”的不同类型更好地 shared_ptr?
【发布时间】:2016-12-11 04:02:09
【问题描述】:

我想使用类似指针的对象

Ownership<Type> m_foo

用于拥有对象和句柄

Reference<Type> m_someFoo

作为另一个上下文中的经典“指针”,而我的 Reference 应该知道原始对象何时不再存在(例如,通过返回 nullptr)并且还应该可以阻止原始对象从删除一小段时间(锁定)。

我知道 shared_ptr(所有权)和 weak_ptr(参考)提供类似的功能。但是,锁定 weak_ptr 并访问原始 ptr 需要创建一个相当慢的 shared_ptr。此外,我无法决定在访问原始 ptr 之前不锁定 weak_ptr(例如,在知道对象现在没有被删除的情况下)。

如下实现 OwnershipReference 是否明智:

  • 所有权知道其引用的地址(例如std::list<Reference<Type>*>
  • 当拥有的对象衰减时,这些References被设置为nullptr
  • 引用所有权中包含指向uint m_lockCount的ptr
  • 锁定时,m_lockCount++,解锁时m_lockCount--
  • 所有权m_lockCount != 0时无法释放对象

此解决方案对于少数Reference 实例和通过References 的高访问率特别可行。

【问题讨论】:

  • " 涉及创建一个相当慢的 shared_ptr"。知道为什么慢吗?当拥有的对象衰减时,这些引用被设置为nullptr,引用包含指向一个uint m_lockCount的ptr,在锁定时,m_lockCount++,在解锁时m_lockCount--,当m_lockCount!= 0时,所有权不能释放对象。另外,我打赌它比你想象的要快得多。
  • 您所描述的一切正是 shared_ptrweak_ptr 旨在为您处理的内容。按原样使用它们,不要尝试手动复制它们。锁定weak_ptr 确实会创建一个新的shared_ptr,但创建速度很快,因为它共享原始share_ptr 的数据指针,并增加其引用计数,直到复制的shared_ptr 超出范围。引用计数的重点是快速复制,并且在锁处于活动状态时不释放拥有的对象。
  • 不要重新实现轮子。
  • 如果你确实重新实现了轮子,请确保你的配置文件以确保你的改进确实是一种改进,并测试它的 bejeeebes 以确保你避免的减速不会做任何事情在你没有考虑过的边缘情况下很重要
  • 为指针Reference命名容器?您是因为简单地转换为prvalue而选择std::move的人吗?

标签: c++ shared-ptr dereference ownership weak-ptr


【解决方案1】:

您提出的替代方案将比shared_ptr/weak_ptr 慢得多,这仅仅是因为使用std::list 作为指向引用的反向指针的想法。如果您只在单线程模式下工作,那将是唯一的额外开销。添加线程,你需要一个锁来原子地操作你的引用计数和引用列表(尽管一旦你有了一个列表,你就不需要计数了)。 shared_ptr\weak_ptr 为您的对象添加了几个指针开销,并且在初始分配之后没有动态分配。

【讨论】:

  • 当然,在大量创建和复制所有权和引用时,引用计数(参见 shared/weak_ptr)是最快的。但是,当经常取消引用引用时,上面的方法更快,因为它的行为类似于指针。你的锁是对的,我需要它作为列表。
  • 如果您的Reference 类阻止Ownership 类释放底层指针,这与使用shared_ptrs 的每个人有何不同?如果这不是真的,那么您必须在尊重 Reference 时操纵锁定计数,此时它与 weak_ptr 没有什么不同
  • 引用只在锁激活时防止对象衰减。我仍然可以决定直接访问 Reference 中的 ptr(可能不是线程安全的,但速度很快)或通过条件增量操作(线程安全锁计数增量)锁定。后者应该仍然比从 shared_ptr 创建 weak_ptr 更快(当然这应该被测试)。
  • 据我所知,我认为有关性能的链接支持这一点,从 weak_ptr 构造 shared_ptr 的唯一成本是用于将对象固定到的原子操作记忆。我看不出你怎么能做得比这更好,因为你最终会得到或多或少相同的逻辑。如果您有一种外部方法来证明特定访问是安全的,我同意您可以从该用例中挤出一点性能,但我会质疑您是否正在优化正确的事情。
猜你喜欢
  • 1970-01-01
  • 2018-09-06
  • 2015-10-23
  • 1970-01-01
  • 2014-03-31
  • 2018-09-08
  • 2011-10-14
相关资源
最近更新 更多