【问题标题】:diffrence between using list<type> and pointers (classic C) for linked lists对链表使用 list<type> 和指针(经典 C)之间的区别
【发布时间】:2015-12-09 04:48:33
【问题描述】:

使用内置的 std::list 而不是像 C 中那样基于指针的自己的链表实现有什么优点/缺点?

是否存在一些特殊情况,其中一个优先于另一个?

【问题讨论】:

  • 如果你知道你在做什么,你知道有充分的理由制作你自己的链表并且你愿意承担额外的工作,那就去DIY指针链表吧,否则坚持使用 std::list。
  • @DenisBlank:这不是同一个问题。
  • 我的问题不是“向量(数组)与列表(链表)”
  • 啊,好吧,我理解错了你的问题。

标签: c++ c linked-list


【解决方案1】:

Walter 提供的答案涵盖了更喜欢 stl 实现的主要原因。考虑使用经典 C 风格实现的主要原因是提高性能。这种提高性能的成本主要是潜在的错误。这可以通过测试和包含一些适当的断言(检查空指针..._

与 Walter 回答中的陈述相反,在某些情况下,高性能列表是一个很好的数据结构选择。

如果您需要自定义列表的性能,但又想避免构建和测试自己的工作,请查看 boost 侵入式列表(单链接和双链接): http://www.boost.org/doc/libs/1_39_0/doc/html/intrusive.html 这些将使您获得与自定义构造相同的性能,并且(几乎)具有 stl 版本的便利性。

【讨论】:

  • 这似乎是一个信息丰富的答案。否决者是否愿意评论如何改进答案?
  • 它不能将std::list 与 C 风格的指针实现进行比较。
  • 它没有回答问题。
  • @juanchopanza 我确认与问题无关
【解决方案2】:

使用std::list 代替您自己的链表实现有很多充分的理由:

  1. std::list 得到保证(通过 c++ 标准库的 标准的实施)按照锡上的解释工作(没有 标准中的错误、异常安全和线程安全)。

  2. std::list 不需要您花时间开发和 测试一下。

  3. std::list 众所周知,因此其他任何人都可以使用 代码(或你以后的生活)可以理解发生了什么 无需先掌握自定义链表 实施。

我真的想不出任何充分的理由来使用您自己的自定义链表。

std::list 通常实现为双向链表。如果只需要单链表,可以考虑std::forward_list

最后,如果您关心性能,则根本不应该使用链表。链表中的元素必须单独分配(并且经常在随机位置插入),因此处理链表通常会导致许多缓存未命中,每一次都会对性能造成影响。

【讨论】:

    【解决方案3】:

    通常,您想使用@Walter 回答的std::list

    但是,通过“侵入式”将下一个(和上一个,如果有的话)指针直接集成到包含的对象中实现的列表可以避免std::list 和其他 STL 容器的几个缺点,这些缺点可能相关也可能不相关给你(引自Boost.Intrusive documentation):

    • 一个对象只能属于一个容器:如果要共享一个对象 在两个容器之间,您要么必须存储这些容器的多个副本 对象或您需要使用指针容器:std::list&lt;Object*&gt;
    • 使用动态分配来创建传递值的副本可能是一种 某些应用程序中的性能和大小瓶颈。 […]
    • 只有对象的副本存储在非侵入式容器中。因此复制 或移动构造函数和复制或移动赋值运算符是必需的。 不可复制和不可移动的对象不能存储在非侵入式 容器。
    • 在 STL 容器中存储派生对象是不可能的 保留其原始类型。

    第二点可能不适用于列表的大多数典型用法,无论如何您都将动态分配元素。

    如果最后一点与您相关,您可能会对Boost.PointerContainer 感兴趣——尽管std::list&lt;std::unique_ptr&lt;Obj&gt;&gt; 通常也能很好地完成这项工作。

    与其自己完全实现一个列表,不如看看前面提到的 Boost.Intrusive 库。

    【讨论】:

    • 这些点与这里有什么关系?使用std::container&lt;std::shared_ptr&lt;&gt;&gt;std::container&lt;std::unique_ptr&lt;&gt;&gt;无法解决哪些应用问题? (请注意,与std::unique_ptr&lt;base&gt; 不同,std::shared_ptr&lt;base&gt; 不需要虚拟析构函数:它知道要删除的正确派生类型,这似乎与您的最后一点相矛盾)
    • 我认为 Boost.Intrusive 提供了先进的方法,这些方法不仅远远超出了 OP 的水平,而且仅在优势大于劣势(包括非标准)的特殊情况下才有用.这里给 OP 的建议是:使用标准库。只有当你非常了解标准库并且你的要求不能被它满足时,你才应该考虑像 Boost.Intrusive 这样的东西。
    猜你喜欢
    • 2011-03-14
    • 2010-12-16
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    相关资源
    最近更新 更多