我开始比较:
然而我注意到,即使在push_back()
,deque似乎也更快。我必须做某些事情错误,我无法相信更通用的容器会胜过特定容器。
我使用谷歌基准测试的代码:
#include "benchmark/benchmark.h"
#include <deque>
#include <vector>
#define NUM_INS 1000
static void BM_InsertVector(benchmark::State& state) {
std::vector<int> v;
v.reserve(NUM_INS);
while (state.KeepRunning()) {
state.PauseTiming();
v.clear();
state.ResumeTiming();
for (size_t i = 0; i < NUM_INS; i++)
v.push_back(i);
}
}
BENCHMARK(BM_InsertVector);
static void BM_InsertDeque(benchmark::State& state) {
std::deque<int> v;
while (state.KeepRunning()) {
state.PauseTiming();
v.clear();
state.ResumeTiming();
for (size_t i = 0; i < NUM_INS; i++)
v.push_back(i);
}
}
BENCHMARK(BM_InsertDeque);
BENCHMARK_MAIN();
结果:
Run on (1 X 2592 MHz CPU )
2016-02-18 14:03:47
Benchmark Time(ns) CPU(ns) Iterations
------------------------------------------------
BM_InsertVector 2820 2470 312500
BM_InsertDeque 1872 1563 406977
在使用元素数量时,我注意到一些差异,但deque总是优于矢量。
编辑:
编译器:gcc version 5.2.1
使用以下内容进行编译:{{1}}
我认为g++ -O3 -std=c++11 push_front.cpp -lbenchmark -lpthread
实际上是工具性的;当我关闭它时,我会得到一个稍微更糟的 deque性能。
答案 0 :(得分:1)
我认为向量较慢,因为你正在调用clear()
,这取决于你的STL实现,可能会释放底层数组存储。
如果是这种情况,那么您的reserve()
电话无效;并且您的矢量不断调整大小,这需要将每个元素移动到新的更大的存储空间。
答案 1 :(得分:1)
持续将元素附加到动态容器中基本上涉及3个成本来源:
让我们从1开始。vector
一直要求内存加倍,deque
分配固定大小的块(deque
通常实现为数组数组,下层数组具有固定的大小)。要求更多的内存可能需要更长的时间,但通常要求更少,但通常情况下,除非你的堆非常分散,一次性要求一个大块是获得一些内存的最快方法。分配一个meg一次可能更快,然后要求千字节1000次。所以很明显vector
最终会在这里有优势(直到容器如此之大,它受到碎片的影响)。然而,这最终不是:你只要求1000个元素。我写了以下代码http://coliru.stacked-crooked.com/a/418b18ff8a81c1c0。它不是很有趣,但它基本上使用了一个简单的分配器来增加全局,以查看执行了多少分配。
在您的基准测试过程中,vector
要求内存11次,而deque
只要求10次。deque
一直要求相同的金额,vector
要求加倍金额。同样,vector
必须调用free
10次。并且deque
0.这似乎是deque
的小胜利。
对于内部簿记,vector
的实施比deque
更简单。毕竟,vector
只是一个动态数组,deque
是一个数组数组,严格来说更复杂。所以这显然是vector
的胜利。
最后,关于操作本身的元素。在deque
中,没有任何东西被移动过。使用vector
,每个新的堆分配也涉及移动所有元素。它可能已经优化为使用memcpy
来处理普通类型,但是甚至可以看到,这是对memcpy
的10个调用来复制1,2,4,8 ... 512个整数。这显然是deque
的胜利。
我可以推测,启动O3
允许在deque
中非常积极地内联许多更复杂的代码路径,减少2的权重。但显然,除非你做得更详细(非常小心!)基准,你永远不会知道。
大多数情况下,这篇文章表明它比简单的专业容器更复杂,而不是更普遍的容器。我会做一个预测(把我的脖子剪掉,就像它一样):如果你增加元素的数量甚至是2或4的因子,你就不会再看到deque
获胜了。那是因为deque
将使堆分配的数量增加2倍或4倍,但向量只会增加1-2倍。
我在此可能会注意到deque
实际上是一种奇怪的数据结构;它理论上是一个数组数组,但在许多实现中,数组要么是一定的大小,要么只是一个元素,无论哪个更大。此外,它的一些大O保证是无稽之谈。 push_back
只是固定的固定时间,因为在C ++中,只对元素本身的操作计入大O.否则应该很清楚,因为它是一个数组数组,顶级数组的大小成比例到已存储的元素数量。最终,顶级阵列的空间不足,你必须重新分配它,移动O(N)指针。所以这不是真的O(1)push_back
。