我应该在非主要容器上使用shared_ptr或weak_ptr吗

Should I use shared_ptr or weak_ptr on not mainly containers?

本文关键字:ptr shared weak 非主要 我应该      更新时间:2023-10-16

我有两个std容器。它们都具有指向相同数据结构的指针。第一个包含所有数据,第二个只包含一些相同的数据。我应该在第二个容器上使用shared_ptr还是weak_ptr

首先,当我阅读参考资料时,我想到在第一个集合中使用unique_ptr。我的第一个集合包含所有数据,它是唯一一个"拥有"的集合。这意味着如果数据不在那里,就应该删除它。但当我试图创建第二个集合时,我不知道该怎么办。我创建了一个唯一的指针,但现在我需要另一个指向同一元素的指针来破坏唯一性,但实际上真正的所有者不是新指针。所以我明白(我希望我没有错(唯一性是在到达元素的路上,而不是(例如(删除它的可能性。所以,shared_ptr。我第一次收藏的时候就有。但现在第二个出现了,我想在这里也使用shared_ptr。访问相同数据的方法可能是两者都有,所以所有者是两种。但在我的情况下,数据总是从前一秒删除。如果我使用weak_ptr,所有者的数量不会增加。在这两种情况下,当第一个集合需要时,元素都将被删除。最后,我使用shared_ptr,因为使用weak_ptr,我需要lock()每行代码中的每一个指针,这会降低它的可读性。但我到底该用什么呢?

听起来你不需要std::shared_ptr,因为你的数据在一个地方。

我建议在拥有的容器中使用std::unique_ptr,然后简单地将原始指针放在第二个和后续容器中。

这是因为你永远不会删除原始指针,但它们指向的数据仍然由智能指针管理,因此当你不再需要它时,它会被释放

尽管有一些负面报道,原始指针在用作其他实体拥有的数据的非所有者访问器时是完全值得尊敬的,这些实体将在适当的时候删除这些数据。

您还没有给出一条关键信息,即您是否可以保证这两个集合具有相同的生存期。如果你能保证两个集合都有相同的生存期,那么对拥有所有东西的集合使用unique_ptr,对另一个使用原始指针(正如@Galik所建议的(是理想的。

如果您不能保证两个生存期匹配,那么您是为两者选择shared_ptr,还是为第一个选择shared_pt,为第二个选择weak,取决于您希望何时销毁对象。听起来只有第一个集合才是真正的所有者,所以你会想要弱指针。

然而,我强烈建议您坚持第一种方法。避免shared_ptr和weak_ptr要干净得多。危险的是,如果你的两个集合有不同的生存期,第一个集合可能会在第二个集合之前被销毁(只是一个放错地方的大括号(,然后当第二个集试图访问时,它会有悬空指针。当然,你可以简单地小心你的变量,但保证两个独立的局部变量始终具有相同的生存期是非常容易出错的。

如果使两个集合元素都属于同一个类,则可以保证它们同时被构造和销毁。当然,这个类应该是什么样子以及哪些代码应该放在哪里的确切细节取决于问题的细节。但是,即使是让它们都是同一结构的唯一成员(和公共成员(这样简单(尽管很奇怪(的事情,也比使用两个局部变量要好。

"每一行代码"是什么意思?通常的模式如下:

if (auto p = wp.lock()) {
    // p is a shared_ptr; use it as often as you need within the block.
}

如果你有一个拥有的容器和一个引用容器,如果所有者破坏了裁判,那么shared_ptr/weak_ptr就是你的选择。

好问题,

根据经验,我发现使用shared_ptr/weak_ptr,甚至扩展使用shared_ptr,往往会导致某种大的模糊设计。

过去有人主张shared_ptr可以被认为是有害的。因为它使所有权浮动。这种所有权应该通过设计来明确我不确定我是否愿意采纳这一建议并予以提倡;但为了回答这个问题,我肯定会在这里重复一遍

此外,可以考虑在任何地方使用shared_ptr与使用垃圾收集是一样的。这只是引用计数,但它最终的行为是一样的。只是性能不太好,过去已经证明,一个好的垃圾收集引擎比所有引用都快(这肯定是因为shared_ptr中需要CPU原子指令和屏障,但我推测。(

也许你应该考虑转移到一个真正好的垃圾收集语言/平台,比如.NET 4上的C#?

否则,如何摆脱直接指针方案并使用标识符,您可以创建一个管理器模式,在该管理器中您的2个索引数据结构是私有的。客户只能通过管理器的API看到和使用标识符(intuint64_t?由您自行决定(。

我发现这种方法的问题是需要在管理器中重复被操纵对象的整个API。这很痛苦,不尊重DRY。

否则,您是否考虑过您的数据结构可能不是天生必要的
我的意思是,不管怎样,当你存储指针时,索引数据结构往往不会那么大。它只是N*sizeof(ptr_t)而不是N*sizeof(value_t)。这突然使std::vector在任何情况下都成为一个优秀的候选人。我的意思是,向量已经是几乎所有用途的最佳数据结构,这一理论有很多倡导者。

如果您的向量只包含指针,请帮自己一个忙,使用boost::ptr_vector来减轻shared_ptr的开销。

我希望我带来了一些观点。