EDIT:我又添加了两个基准测试,以比较 realloc 与 C 数组的使用以及 Reserve() 与 std::vector 的使用。从最后的分析看来,realloc 的影响很大,即使只调用了 30 次。检查文档,我猜这是因为 realloc 可以返回一个全新的指针,复制旧的指针。
为了完成该场景,我还添加了用于在初始化期间完全分配数组的代码和图表。区别于reserve()
是有形的。
编译标志:只有图中描述的优化,使用 g++ 编译,仅此而已。
原问题:
我做了一个基准std::vector
与新/删除数组相比,当我添加 10 亿个整数时,第二个代码比使用向量的代码快得多,尤其是在打开优化的情况下。
我怀疑这是由于向量内部调用realloc太多次造成的。如果向量每次被填充时大小不会增加一倍(这里数字 2 没有什么特别的,重要的是它的大小呈几何级数增长),就会出现这种情况。
在这种情况下,对 realloc 的调用只会是O(log n)
代替O(n)
.
如果这就是导致第一个代码缓慢的原因,我如何告诉 std::vector 以几何级数增长?
请注意,在这种情况下调用reserve一次可以工作,但在提前不知道push_back的数量的更一般情况下则不行。
黑线
#include<vector>
int main(int argc, char * argv[]) {
const unsigned long long size = 1000000000;
std::vector <int> b(size);
for(int i = 0; i < size; i++) {
b[i]=i;
}
return 0;
}
蓝线
#include<vector>
int main(int argc, char * argv[]) {
const int size = 1000000000;
std::vector <int> b;
for(int i = 0; i < size; i++) {
b.push_back(i);
}
return 0;
}
绿线
#include<vector>
int main(int argc, char * argv[]) {
const int size = 1000000000;
std::vector <int> b;
b.reserve(size);
for(int i = 0; i < size; i++) {
b.push_back(i);
}
return 0;
}
red line
int main(int argc, char * argv[]) {
const int size = 1000000000;
int * a = new int [size];
for(int i = 0; i < size; i++) {
a[i] = i;
}
delete [] a;
return 0;
}
橙色线
#include<vector>
int main(int argc, char * argv[]) {
const unsigned long long size = 1000000000;
int * a = (int *)malloc(size*sizeof(int));
int next_power = 1;
for(int i = 0; i < size; i++) {
a[i] = i;
if(i == next_power - 1) {
next_power *= 2;
a=(int*)realloc(a,next_power*sizeof(int));
}
}
free(a);
return 0;
}
编辑:检查.capacity()
正如所建议的,我们看到增长确实是指数级的。那么为什么向量这么慢呢?