【问题标题】:Why is std::vector so much more popular than std::deque? [duplicate]为什么 std::vector 比 std::deque 更受欢迎? [复制]
【发布时间】:2012-11-25 08:40:04
【问题描述】:

可能重复:
Why would I prefer using vector to deque

我很好奇为什么std::vectorstd::deque 更受欢迎。双端队列在查找方面几乎同样有效,在插入方面效率更高(没有 vector::reserve)并允许在前面插入/删除。

Herb Sutter 曾经推荐过 if you want to use vector, just prefer deque(我在解释)。然而,在最近关于Writing Modern C++ 的一次谈话中,他再次强烈建议将std::vector 视为默认容器。根据我之前链接的GOTW,即使标准也有类似的措辞。

这种差异有原因吗?只是vector更简单,知名度更高,还是有技术原因?还是vector 只是一个更酷的名字..?

【问题讨论】:

  • 只是我的看法,但总的来说我认为我们使用前端不如使用后端。
  • IIRC Scott Meyers 和 Bjarne 都推荐 vector 作为“默认容器”。另外,afaik,它是唯一一个底层内存模型与 C API 兼容的标准容器(所以我想这比双端队列要好?)
  • @JanDvorak:不,follow the white rabbit
  • @JanDvorak:不知道,我不太关心 Java ;)
  • 另外,vector 很容易适应 CPU 缓存,并且向量元素上的算术运算可以很容易地向量化。如果可能的话,使用deque 做到这一点并不容易

标签: c++ vector deque


【解决方案1】:

我不能为任何人说话,但我可以为自己说话。

当我第一次读到std::deque 时,我觉得它很酷,有一段时间我不仅把它当作默认容器,而且几乎是我使用的唯一容器。

然后有人问为什么,我详细阐述了它的优点,为什么它是几乎可以用于所有东西的最佳容器,以及它如何比std::vector 更通用。

幸运的是,质疑我决定的人很有说服力,我做了一些测试。测试表明,在几乎所有情况下,std::deque 都比std::vector 慢——通常是一个很大的因素(例如,大约 2)。事实上,在我使用std::deque 编写的代码中,仅将std::deque 替换为std::vector 在除少数情况之外的所有情况下都可以加快速度。

从那以后,我在少数情况下使用了std::deque,但绝对不要再将其视为默认值。一个简单的事实是,在通常的实现中,对于大多数目的而言,它明显比std::vector 慢。

不过,我应该补充一点,我有理由确信,通过正确的实现,它可能几乎在所有情况下都等同于std::vector。大多数人使用的表示从渐近的角度来看无疑是很棒的,但在现实世界中(出于多种目的)并没有那么完美。

【讨论】:

  • +1:很好的答案!很高兴您实际对其进行了测试。
【解决方案2】:

std::vector 很好理解、简单并且与 C 兼容(无论是在内存布局方面,还是在使用指针作为迭代器方面)。

对于某些操作,它也比std::deque 更有效。按索引访问元素就是一个例子。

对于给定的任务,使用能很好地完成工作的最简单的容器是有意义的。在许多情况下,最简单的容器是std::vector

【讨论】:

  • +1 对于奥卡姆的剃刀答案。
【解决方案3】:

人们使用 std::vector 而不是 std::deque 的原因很简单。它们与许多 C 库接口,并且它们具有 functions 的参数,这些参数需要指向连续存储的指针,而 std::deque 不能(不能)保证。

另一个原因是,当您根据 std::deque 构建代码并且您的需求发生变化以致必须支持连续访问时,您将需要进行一些重构。

我不得不提一下,libraries 的作者声称已经创建了更高效的向量实现,以便在 capacity 增加时克服低效率问题。

【讨论】:

    【解决方案4】:

    std::deque 的结构有点复杂,这使得天真的迭代比std::vector 更昂贵。插入std::vector 及其重新分配往往不是大问题,尤其是在使用reserve() 并且仅附加到末尾时。此外,std::vector 的失效规则更易于理解,尽管 std::deque 的一个优点是对象在仅在任一端插入/删除时保持原位(请注意,std::deque 迭代器在每次插入时都会失效,独立于插入发生的地方)。 std:vector 的另一个优点是保证这些值在内存中是连续的,从而减少了内存分配。

    我想,我会建议使用std::deque 算法一直优化以使用分段序列(我不知道任何标准 C++ 库都进行此优化)并且用户始终使用算法访问序列(据我可以看出,只有一小部分用户考虑使用算法的选项)。否则,我会怀疑 std::deque 只有在您利用其特定属性(例如,对象保持原位并且您可以在最后插入/删除)时才在性能方面是更好的选择。不过,值得对这两种选择进行分析。

    【讨论】:

    • +1 - 但我不会说 vector 在内存分配计数方面比 deque 有太多优势。当然,双端队列可能会分配更大的数量;但通常 deque 进行的分配与相关对象的大小相比足够大,这几乎不是问题。
    • 分配的数量对于小型实例显然无关紧要。对于大型实例,std::vector 进行 O(log(c.size())) 分配,而 std::deque 进行 O(c.size()) 分配。当然,它可能有更好的机会分配它的多个块而不是一大块......
    • 是的,但我不认为在我们谈论的尺度上渐近是有用的。与实际用数据填充任何此类结构并使用所述数据执行有用的工作相比,即使是物理内存大小的这些结构中的一个也是花生。 (也就是说,我不认为n 在真实硬件上变得足够大)当n 变大时,必须支持单个巨大内存块的碎片问题似乎更重要,这对@ 来说是一个优势987654337@.
    【解决方案5】:

    除了std::vector是最广为人知的容器类外,它还比std::deque有几个优点,分别是:

    • 典型的std::deque 需要额外的间接访问元素,这与std::vector 不同。
    • std::deque 中的迭代器必须是智能指针,而不是 std::vector 中的指针。
    • std::vector 的元素保证是连续的,因此它与将数组作为参数的 c 样式函数兼容。
    • std::deque 不支持控制容量和重新分配的时刻。

    特别是最后一点值得注意。

    【讨论】:

    • Iterators in case of std::deque must be smart pointers and not pointers as in case of std::vector.
    • @BillyONeal:在语义上,std::vector 的迭代器不需要很聪明,因为元素保证是连续的。而在std::deque 的情况下,迭代器实现必须足够聪明才能跳转到下一个块并检测下一个元素。当然,标准并没有说明迭代器类的实现,但通常情况下就是这样。
    • 可能——但我不明白为什么这会影响图书馆的用户。一致的 C++ 实现必须同时向用户提供vectordeque——实现的复杂性取决于实现。我不认为用户关心这些事情。 (还应该注意,至少有一种流行的编译器(MSVC++)总是使用真实的对象作为迭代器类型,而不是指针)
    猜你喜欢
    • 1970-01-01
    • 2019-06-11
    • 2012-03-07
    • 2013-02-05
    • 2015-01-15
    • 2020-10-25
    • 2014-10-24
    • 2012-11-16
    • 1970-01-01
    相关资源
    最近更新 更多