在不模拟循环数据结构的单线程应用程序中,何时需要使用引用计数?

13

Rust可以通过Rc非常优雅地处理引用计数。似乎社区的许多成员更喜欢使用语言的所有权/借用语义而不是使用Rc。这样编写的程序更简单,但除了循环引用之外,是否有必要呢?

显然,在跨线程方面,情况变得更加复杂。因此,为了简化我试图学习的内容,"在单线程应用程序中,除了作为编写时优化之外,是否需要引用计数?" 这是否是高级Rust技能的反模式?


1
这个回答解决了问题吗? - user2722968
@user2722968,我喜欢你在那个问题中的回答,但我发现这个问题更容易理解和更相关。我希望我们能够将两者结合起来。 - John Kugelman
2个回答

7
我认为@kmdreko的基本正确,但是一个更难以模拟而没有Rc的例子是过滤具有“繁重”数据的查询,将其缩小到多个所有者。 基本上,每当您处理进入多个其他过滤集的“集合”时,其中过滤器可能重叠时。例如,如果您收集了1000张图像,并调用OpenCV(或类似软件)来查找原始集合中哪些图像具有鸟类,哪些图像中有树木,结果集可能会重叠。 因此,如果您不使用Rc(或类似技术),则要么复制这些潜在巨大的图像(可能不需要),要么保留对它们的引用。好吧,但是然后您就无法释放原始图像集,因为它拥有结果集所引用的图像。虽然有解决方法(仅在一个或多个过滤条件说要这样做时保存图像),但由于使用的内存模型,这会导致深度整合程序的潜在分离部分。或者只需使用Rc,其他人可以轻松地“访问”它,带入的任何东西都可以被“完成”,并且释放未引用的所有内容,同时仍保留仍在使用的集合部分。
我同意Rc及相关技术可能会被过度使用。 我在C++中遇到这种情况的次数太多了,人们到处扔shared_ptr并认为这时它们就“好”了(直到应用程序或DLL关闭,并且开始出现“为什么我的应用程序总是在退出时崩溃?”的请求)。 也就是说,即使是单线程,有时也需要共享所有权,以便可以将其传递给未知数量的消费者以备后用。与大多数工具一样,有解决某些问题的方法,但这可能会带来更多的痛苦。

请查看im crate,这是一个很好的例子。 - Aiden4

5
当你需要共享所有权时,应该使用 Rc。使用 Arc 没有什么不同,但是它可能更常见,因为标准线程机制(如 std::thread::spawn)需要所有权。
在单线程环境中,如果您的数据更像图形(可以具有循环依赖,但不一定),您仍然会使用 Rc。在这种情况下,您不能使用基本引用。您可以将类似于图形的关系标准化表示,并使用索引或 ID 代替引用,但这可能并不总是可行或可取。当然,如果您在可以以分层方式表示结构的情况下使用 Rc,则使用 Rc 将是不必要的。
此外,有许多原因为什么外部函数或结构需要一个泛型类型或函数为 'static。在这些情况下,移动、clone() 或共享(使用 Rc)是解决方案。
我不认为 Rc 本身就是反模式,它只是另一个工具,但有时可以避免使用它,从而得到更清晰的关系和/或更好的性能。我经常看到 Rust 新手慷慨地使用 Rc,他们还没有完全掌握借用检查器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接