【问题标题】:Syntax for converting expired weak_ptr<T> to shared_ptr<T>将过期的 weak_ptr<T> 转换为 shared_ptr<T> 的语法
【发布时间】:2015-07-18 06:52:53
【问题描述】:

根据我的阅读,shared_ptr&lt;T&gt; 在强引用和弱引用都被删除之前不会被解除分配。

我了解共享对象在没有更多强引用时被视为已过期。因此,weak_ptr&lt;T&gt; 的标准 lock() 函数在这种情况下会失败,因为该对象被视为“过期”。

但是,如果共享指针的删除器被覆盖,这样托管对象不会被删除,那么从 weak_ptr&lt;T&gt; 生成 shared_ptr&lt;T&gt; 应该是有效的 - 但我找不到正确的语法来执行此操作。

std::shared_ptr<int> s_ptr(new(42), D());
std::weak_ptr<int) w_ptr(s_ptr);
s_ptr.reset();

s_ptr = std::shared_ptr<int>(w_ptr, false);

编辑

为了进一步澄清这一点,我正在尝试构建一个可重用shared_ptr&lt;T&gt; 的对象池。这背后的原因是因为每次使用 shared_ptr 都会导致一个或多个堆内存分配。因此,我为每个 shared_ptr&lt;T&gt; 添加了一个删除器,它存储了一个 weak_ptr&lt;T&gt; 引用,这样删除器就会被调用,它应该能够将自己重新添加到可用的 shared_ptr&lt;T&gt; 对象池中(托管对象完好无损) .通过将weak_ptr&lt;T&gt; 存储在shared_ptr&lt;T&gt; 的删除器中,它不应该阻止删除器被调用。

最终目标是获得一个不进行一致堆分配的智能指针 - 或者至少只有一小部分。

【问题讨论】:

  • 我不认为这种用途是有意的。此外,是什么让您如此确定指针在不再需要后保留在任何地方?只是好奇,你想解决什么?顺便说一句:你的第一句话到底是什么意思?究竟是什么没有被释放?对我来说这听起来模棱两可。
  • 这对我来说听起来既无意义又危险,一个 XY 问题。实际目标是什么?
  • @Ulrich - 我的意思是第一句话比控制块仍然存在是强指针计数达到零。参考:“在 std::weak_ptr 计数器也达到零之前,控制块不会自行释放。”来自en.cppreference.com/w/cpp/memory/shared_ptr
  • @EJP,我正在尝试构建一个 shared_ptr 的对象池。不是托管对象池,而是对象的 shared_ptr 池。我保留对任何分配的 shared_ptr 的weak_ptr 引用,以保持其存活以供回收。
  • 那么为什么删除器不将对象返回到池中呢?

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


【解决方案1】:

根据我的阅读,shared_ptr 在强引用和弱引用都被删除之前不会被释放。

错了。 std::shared_ptr 有两个块 - 一个包含引用计数等的控制块,然后是实际数据的另一个块。

当共享计数变为 0 时,数据块(通常)被释放。这就是为什么从过期的std::weak_ptr 中创建std::shared_ptr 是非法的。

另一方面,你为什么会想要这个功能?它破坏了std::weak_ptr 的全部要点,即能够“存储”指向std::shared_ptr 存储的对象的指针而不增加其引用计数。 如果您想这样做,请使用std::shared_ptr

【讨论】:

  • 我确实提到我正在重写删除器函数,这样托管对象就不会被删除。这种用法背后的原因是为了重用shared_ptrs。
  • 真的,对不起。你有什么理由不能只使用shared_ptrs 的容器?
  • shared_ptr 的容器将保持对托管对象的强引用,因此使用计数永远不会达到零 - 因此删除器不会触发。 (我正在使用删除器函数将 shared_ptr 实际返回到对象池)
  • 因为这有点像黑客,我认为weak_ptr 不会做你想做的事,因为这正是weak_ptr 试图阻止的。为了做你想做的事,我建议你只存储一个指向对象的原始指针。
  • 我完全同意你的看法——除了从原始指针创建 shared_ptr 会导致控制块的堆分配——这正是我想要避免的。
【解决方案2】:

如果池化控制块是个好主意,那么库实现可能已经在这样做了。事实上,new 本身的实现可能已经在进行池化以支持类似的内存使用模式。

此外,您可以通过使用make_shared 而不是调用new 并将其传递给shared_ptr 构造函数来实现我认为的目标;这个辅助函数存在的原因之一是它可以被编写为使用 single 分配来分配控制块 您正在创建的新对象同时。

【讨论】:

  • 使用make_shared 的困难在于它不允许自定义删除器。我可以找到零种方法来使用 make_shared 的自定义删除器逻辑。这意味着托管对象必须被堆删除。
  • 您是否暗示可以构造和破坏 shared_ptr 的无限循环而不用担心内存碎片,因为默认内存分配器池的控制块已构建?
猜你喜欢
  • 2012-07-22
  • 1970-01-01
  • 2019-10-20
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-06
  • 1970-01-01
相关资源
最近更新 更多