为什么我更喜欢使用vector来deque

时间:2011-03-17 20:57:53

标签: c++ stl vector deque

由于

  1. 它们都是连续的内存容器;
  2. 功能明智,deque几乎所有的矢量都有,但更多,因为它在前面插入效率更高。
  3. 为什么有人喜欢std::vectorstd::deque

10 个答案:

答案 0 :(得分:100)

deque中的元素在内存中是连续的;保证vector个元素。因此,如果您需要与需要连续数组的普通C库进行交互,或者您需要(很多)关注空间局部性,那么您可能更喜欢vector。此外,由于有一些额外的簿记,其他操作可能(略微)比同等的vector操作更昂贵。另一方面,使用vector的许多/大型实例可能会导致不必要的堆碎片(减慢对new的调用)。

另外,正如elsewhere on StackOverflow所指出的,这里有更多好的讨论:http://www.gotw.ca/gotw/054.htm

答案 1 :(得分:31)

要知道差异,应该知道deque通常是如何实现的。内存以相同大小的块分配,并且它们被链接在一起(作为数组或可能是向量)。

因此,要找到第n个元素,您会找到相应的块,然后访问其中的元素。这是恒定时间,因为它总是正好2次查找,但仍然比矢量更多。

vector也适用于需要连续缓冲区的API,因为它们既可以是C API,也可以在获取指针和长度方面更加通用。 (因此你可以在下面有一个向量或一个常规数组,并从你的内存块中调用API)。

deque最大的优势在于:

  1. 从两端增长或缩小收藏时
  2. 当你处理非常大的收藏品时。
  3. 在处理bool时,你真的想要bool而不是bitset。
  4. 其中第二个鲜为人知,但对于非常大的收藏尺寸:

    1. 重新分配的成本很高
    2. 必须查找连续内存块的开销是限制性的,因此您可以更快地耗尽内存。
    3. 当我在过去处理大型集合并从连续模型转移到块模型时,我们能够在32位系统中耗尽内存之前存储大约5倍的集合。这部分是因为,在重新分配时,它实际上需要在复制元素之前存储旧块以及新块。

      说完这一切之后,您可能会在使用“乐观”内存分配的系统上遇到std::deque问题。虽然尝试为vector重新分配请求大缓冲区大小的尝试可能会在bad_alloc的某些时候被拒绝,但分配器的乐观性质可能总是授予较小的请求。 deque请求的缓冲区,可能导致操作系统终止进程以尝试获取某些内存。无论选择哪一个都可能不太令人愉快。

      在这种情况下的解决方法是设置系统级标志以覆盖乐观分配(并不总是可行)或稍微更手动地管理内存,例如:使用您自己的分配器来检查内存使用情况或类似情况。显然不理想。 (这可能会回答你的问题,因为更喜欢矢量...)

答案 2 :(得分:25)

我已经多次实现了vector和deque。从实现的角度来看,deque非常复杂。这种复杂性转化为更多代码和更复杂的代码。因此,当您选择deque over vector时,通常会看到代码大小。如果您的代码仅使用向量优于的东西(即push_back),您也可能会遇到小的速度命中。

如果你需要一个双端队列,deque是明显的赢家。但是如果你在后面进行大部分插入和擦除,矢量将成为明显的赢家。如果您不确定,请使用typedef声明容器(因此很容易来回切换),并进行测量。

答案 3 :(得分:6)

std::deque没有保证连续内存 - 而且索引访问通常会慢一些。 deque通常被实现为“向量列表”。

答案 4 :(得分:2)

根据http://www.cplusplus.com/reference/stl/deque/,“与矢量不同,deques不能保证其所有元素都在连续的存储位置,从而消除了通过指针算术安全访问的可能性。”

Deques有点复杂,部分原因是它们不一定具有连续的内存布局。如果您需要该功能,则不应使用双端队列。

(以前,我的回答是缺乏标准化(来自上面的相同来源,“deques可能以不同的方式由特定库实现”),但这实际上适用于任何标准库数据类型。)

答案 5 :(得分:0)

deque是一个序列容器,允许随机访问它的元素,但不保证它具有连续的存储。

答案 6 :(得分:0)

我认为对每个案例进行性能测试都是个好主意。并决定依靠这些测试。

在大多数情况下,我更喜欢std::deque而不是std::vector

答案 7 :(得分:0)

根据these test results (with source).

,你不喜欢矢量来欺骗

当然,您应该在您的应用程序/环境中进行测试,但总结如下:

  • push_back对于所有
  • 基本相同
  • 插入,以双端队列擦除比列表快得多,并且比向量
  • 快一点

Some more musings, and a note to consider circular_buffer.

答案 8 :(得分:0)

一方面,矢量通常比deque更快。如果您实际上不需要 deque的所有功能,请使用矢量。

另一方面,有时你需要向量不能给你的功能,在这种情况下你必须使用双端队列。例如,我挑战任何人尝试重写this code,而不使用双端队列,并且不会大幅改变算法。

答案 9 :(得分:-1)

请注意,向量存储器会随着数组的增长而重新分配。如果您有指向矢量元素的指针,它们将变得无效。

此外,如果您删除元素,则迭代器将变为无效(但不是“ for(auto ...)”)。

编辑:将“双端队列”更改为“向量”