为什么C++标准库没有具有连续内存的deque版本?

djs*_*rew 3 c++ stl data-structures c++11

根据我的理解,deque会根据您的需要分配新的常量内存块,而不保证它们是连续的.这确保从任一侧删除不会使当前指向双端队列的任何迭代器无效.

这种内存布局在某些情况下很方便,但它通常比连续存储内存慢.

更快的连续内存的首选容器是矢量,但它不允许您从前面推或弹.

我不明白为什么会这样.

我确信可以实现一个使用连续内存的双端队列,而且看起来它会严格优于向量.它的内存布局同样快,它还可以从前面有效地推/弹.

不仅如此,我觉得从设计角度来看也更有意义.连续的双端队列将是它速度的首选,并且当它的内存布局更好地适应手头的问题时,将使用非连续的双端队列.

如果我遗失某些东西或者看上去非常短视,请告诉我.为什么标准库中没有连续的双端队列?

Jon*_*ely 9

标准库中的容器并不意味着涵盖所有可能的用例,它们只是一些有用的数据结构(主要是)非重叠属性(如果将四个关联容器统计为一个单独的族,并且四个无序)容器作为另一个家庭).

对于连续内存,请使用向量.要进行高效拼接,请使用列表.为了在任何一端进行有效的插入和移除而不需要大量的重新分配和改组,请使用deque等.

如果你想要一个不同的数据结构然后编写它,这就是STL设计的要点:遵循相同原则的任何其他容器都将与STL风格的算法完美配合.

你提出的结构比矢量有更多的开销,需要四个指针而不是三个.它可能需要前端容量和后容量成员函数,因此您可以知道在任一端插入是否会重新分配和/或使迭代器无效.当它在一端用完空间时,你必须决定是否重新分配或者只是将一切都移动到另一端的自由空间中.根据使用模式的不同,做出错误的决定可能会很昂贵(例如,重新分配并在两端都有更大的增长空间可能会更好,但这可能会导致一端浪费大量空间,如果你洗牌而不是重新分配你可能只是推迟不可避免的事情,并且无论如何都必须重新分配).

但这些都不是无法解决的问题,所以原则上没有什么能阻止你写这样的容器.这并不意味着它必然需要在标准库中.

标准库也没有像Boost.Container的flat_map和stable_vector这样的容器,但您可以在第三方库中找到它们.同样,这种可扩展性是STL设计的重点.


jal*_*alf 5

它已经存在。您可以在向量的前面插入。

是的,当然,它使引用和迭代器无效,并要求复制(或移动)向量的内容,但如果您想要连续内存,这是您必须做出的权衡。

双端队列为您提供的是保证在任一端插入不会使对现有元素的引用无效。这是唯一可能的,因为它使用连续内存。

  • @djscrew:实现它,放到 GitHub 上,提交到 Boost Library Incubator。 (3认同)
  • @djscrew,这需要您提前决定元素的最大数量,并预先分配所有内存。 (2认同)
  • @djscrew:在上面的大纲中,arena 按需增长,你最终得到一个容器,在该容器上迭代器在插入时失效(不是所有插入,而是那些增加缓冲区的插入),这是 deque 的主要优势。如果您只想避免分段分配中的潜在缺陷(在 VS 的情况下接近列表),那么它可以在 vector 之上轻松实现。我不认为它是一个通用容器,并且怀疑它是否应该在标准库中。 (2认同)
  • @djscrew 是肯定的,但它与双端队列完全不同,因为双端队列提供的保证是引用保持有效或*所有*插入到前面或后面。你的提议只能达到一些预先保留的限制。我并不是说您提出的建议行不通或没有用(并且可能会被制作为围绕向量的相当简单的适配器类),但它不会像双端队列那样。 (2认同)