由于
为什么有人喜欢std::vector
到std::deque
?
答案 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
最大的优势在于:
其中第二个鲜为人知,但对于非常大的收藏尺寸:
当我在过去处理大型集合并从连续模型转移到块模型时,我们能够在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).
,你不喜欢矢量来欺骗当然,您应该在您的应用程序/环境中进行测试,但总结如下:
答案 8 :(得分:0)
一方面,矢量通常比deque更快。如果您实际上不需要 deque的所有功能,请使用矢量。
另一方面,有时你做需要向量不能给你的功能,在这种情况下你必须使用双端队列。例如,我挑战任何人尝试重写this code,而不使用双端队列,并且不会大幅改变算法。
答案 9 :(得分:-1)
请注意,向量存储器会随着数组的增长而重新分配。如果您有指向矢量元素的指针,它们将变得无效。
此外,如果您删除元素,则迭代器将变为无效(但不是“ for(auto ...)”)。
编辑:将“双端队列”更改为“向量”