使用 std::unique_ptr 的双向链表

Posted

技术标签:

【中文标题】使用 std::unique_ptr 的双向链表【英文标题】:Doubly Linked List Using std::unique_ptr 【发布时间】:2013-03-01 08:04:27 【问题描述】:

有人建议实施吗?前几天我在家里试过这个,发现移动语义太难建立一个先前的链接或简单的链表。如果使用 std::unique_ptr 制作树,则很容易。当然,由于复制/分配,std::shared_ptr 可以轻松实现这个问题。那么怎么样呢?

【问题讨论】:

为什么每个人都投票关闭? 我投票赞成关闭,因为我没有看到 OP 的任何努力。没有代码发布 OP 自己尝试过的内容。 @Nawaz 这并不意味着它“不是一个真正的问题”。我会说“这个问题没有表现出任何研究努力”,但第二句话又说他花时间尝试了一些东西。但这并不是关于为什么他的代码的问题,所以我看不出为什么这是相关的。 这不是一个很接近的问题,这是一个很好的问题。 您的意思是只使用 unique_ptr?对我来说似乎是不可能的,因为在双向链表中你有两个指向每个元素的指针,因此它们不能同时是unique_ptrs。另一种选择是列表,其中nextunique_ptrs,而last 是普通的旧指针 - 乍一看我没有看到太多问题。 【参考方案1】:

由于问题已重新打开,我将发表我的评论作为我认为的答案:

如果你的意思是使用 only unique_ptr,那将是不可能的,因为在双向链表中你有 两个 指向每个元素的指针,因此它们不能都是 unique_ptrs。 (这会以某种方式与 unique 部分相矛盾......)

为了澄清,让我们考虑三个元素的列表:A <-> B <-> C 这里A 将包含一个unique_ptr next,指向B,因此拥有BC 将有一个 unique_ptr prev,同时指向 B - 并拥有它。拥有同一个对象的两个 unique_ptrs 违反了 unique_land 定律,由于unique_ptr 的只能移动属性,您必须付出邪恶的努力才能实现它。

替代方法是一个列表,其中next 指针是unique_ptrs,而last 指针是普通的旧 C 指针 - 我没有看到太多问题,所以我不认为这是你想要什么。

但是如果您有类似“半唯一列表”的想法,请提供一些代码并告诉我们您有什么问题 - 我们很乐意提供帮助 :)

【讨论】:

没有考虑半唯一列表。我可以通过 new easy 使用动态内存从 C 指针构建双向链表。使用 std::shared_ptr 提供实现也很容易。这不是问题。我没有发布代码,因为我已经在家里尝试过,但没有成功,不得不求助于 std::shared_ptr。我的问题是是否有人知道如何仅使用 std::unique_ptr 来实现双向链表。我只能创建一个“半名单”解决方案,因为我发现移动机制不足。有没有办法做到这一点?提供部分唯一性的好答案。 查看我回答的第一部分。我放了一段来澄清为什么不可能有unique_ptr-only-list。 那么这就是我寻求的答案。我感谢你提供它。如果其他人认为他们可以仅使用 std::unique_ptr 实现双向链表,请随时发布解决方案。 如果要添加虚拟节点怎么办?我们在最后一个节点和头部的虚拟节点上有 unique_ptr - 看起来不太好。 @Gusev Slava 你想在哪里添加虚拟节点?你能提供一些显示问题的代码吗?【参考方案2】:

这是我使用的,

https://gist.github.com/mukunda-/153d802065c130e2956c

当然是使用“半唯一”方法,因为这是唯一可能的方法。

它的作用是控制分配给它的 unique_ptr,并且与列表中的项目的任何交互都使用普通指针完成。如果您从列表中拉出一个项目,那么您将获得所有权。

本质上,它为您提供了使用智能指针自动删除的便利。当然,如果您在处理其中一个对象时删除列表对象,它会中断,在这种情况下,您需要一个 shared_ptr 列表。

【讨论】:

【参考方案3】:

是的,它可以通过使用任何指针(下一个或上一个)作为 unique_ptr 和另一个作为原始指针来完成。 请参阅 CppCon 2016:Herb Sutter “C++ 中的无泄漏……默认情况下”。 CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.”

【讨论】:

以上是关于使用 std::unique_ptr 的双向链表的主要内容,如果未能解决你的问题,请参考以下文章

数据结构01- 单链表双端链表双向链表无序链表有序链表

OJLeetcode链表双指针160. 相交链表

Java单链表双端链表有序链表实现

21. 合并两个有序链表简单链表双指针

一些 std::unique_ptr 使用和“陷阱”

将 std::unique_ptr 的子类与 std::variant 一起使用