C++ 还有另一个动态数组vs.std::vector,但是

C++ 还有另一个动态数组vs.std::vector,但是,c++,performance,arrays,optimization,vector,C++,Performance,Arrays,Optimization,Vector,…嗯,我得到了奇怪的结果 我对std::vectorvs.动态数组的性能感到好奇。鉴于在这个问题上已经有很多问题,如果我没有经常得到这些“矛盾”的结果,我就不会提到它:向量比新int[]要快!我一直认为,如果有任何性能差异,它将始终有利于动态阵列。这一结果如何可能 代码如下: int numElements = 10000000; long j = 0; long k = 0; vector<int> intVector(numElements); int* intArra

…嗯,我得到了奇怪的结果

我对
std::vector
vs.动态数组的性能感到好奇。鉴于在这个问题上已经有很多问题,如果我没有经常得到这些“矛盾”的结果,我就不会提到它:
向量
新int[]
要快!我一直认为,如果有任何性能差异,它将始终有利于动态阵列。这一结果如何可能

代码如下:

int numElements = 10000000;
 long j = 0;
 long k = 0;

 vector<int> intVector(numElements);
 int* intArray = new int[numElements]; 

 clock_t start, finish;
 start = clock();

 for (int i = 0; i < numElements; ++i)
  intVector[i] = i;
 for (int i = 0; i < numElements; ++i)
  j += intVector[i];

 finish = clock();
 cout << "j: " << j << endl;
 cout << "Total duration: " << (double) finish - start << " ms." << endl;

 // Test Control.
 start = clock();

 for (int i = 0; i < numElements; ++i)
  intArray[i] = i;
 for (int i = 0; i < numElements; ++i)
  k += intArray[i];

 finish = clock();
 cout << "k: " << k << endl;
 cout << "Total duration: " << (double) finish - start << " ms." << endl;
int numElements=10000000;
长j=0;
长k=0;
向量积分向量(numElements);
int*intArray=新的int[numElements];
时钟没有开始,结束;
开始=时钟();
对于(int i=0;icout我的猜测是,操作系统直到第一次被访问时才分配物理内存。
vector
构造函数将初始化所有元素,因此内存将在开始计时时分配。阵列内存未初始化(可能未分配),因此该时间可能包括分配


尝试将数组初始化更改为
int*intArray=newint[numElements]()
初始化其元素的值,看看这是否会改变结果。

对于所有实际用途,以这种方式使用时,它们的速度完全相同。vector的运算符[]通常是这样实现的[MSVC版本]:

const_reference operator[](size_type _Pos) const
{   // subscript nonmutable sequence
    return (*(_Myfirst + _Pos));
}
。。。这与:

const_reference operator[](size_type _Pos) const
{   // subscript nonmutable sequence
    return _Myfirst[_Pos];
}
您的测试基本上只是测试编译器内联代码的能力,在这里它似乎做得很好

至于差异的解释,您得到的任何答案通常都是假设的,没有看到分解。这可能与更好的缓存有关,寄存器在第一种情况下使用得更好(尝试交换测试顺序,看看会发生什么),等等。值得注意的是,向量的内存将在测试开始之前被访问,测试的方式是将向量中的所有内容初始化为T()

不幸的是,我们不能简单地编写这样的小微测试并从中得出一般性结论。在系统和优化编译器变得如此复杂之前,我们曾经能够做得更多,但现在涉及的变量太多,除了真实世界的测试之外,无法做出有意义的结论


出于同样的原因,我们通常希望任何对性能认真的人都积极地分析他们的代码,因为事情变得太复杂了,人们无法正确地确定代码中的瓶颈,除非存在明显的算法低效(我经常看到,即使是对汇编和计算机体系结构有着比我高得多的理解的专家程序员,在我用分析器检查他们的假设时也会犯错误)。

我只是做了这个实验。尽管我认为我已经发现了奇怪的行为,但确实如此

再次重复你的代码。那就是

benchmark vector
benchmark array

benchmark vector
benchmark array

你会注意到,第二次你会得到不同的数字。我猜?页面错误。由于某种原因,向量不会导致页面错误,而数组方法会。加载页面后,两者将以大致相同的速度运行(即:第二次会发生什么情况)。到目前为止,有人知道如何打印进程中的页面错误数吗?

尝试更长时间的循环,至少几秒钟。如果像这样使用向量,应该几乎没有区别,除非编译器进行了一些奇怪的优化。还可以尝试禁用优化。好吧,用100M(而不是10M)进行尝试与之前一样,给出了~270ms vs~360ms,因此结果没有差异。但是,如果不进行优化,std::vector会损失大量时间。对于10M元素,它在~1400 ms vs仅~80 ms后完成。因此,这是否意味着可以优化vector类以提供比动态阵列更好的性能?我在系统上得到了相反的行为,maybe因为我正在运行一堆其他东西。Vector-2203和new-63。@Kristian:如果不进行优化,对Vector的每次访问都需要一个函数调用,这将比内联的等效函数慢几个数量级。它还可以检查索引是否在每次访问的范围内。经过优化,这两个版本应该会产生非常好的效果类似的代码。您使用的是什么操作系统(请参阅Mike Seymour的答案以了解它的重要性)?请记住最后一段。人工测试几乎是无用的。找到一个真正的问题,对其进行基准测试,并在基准测试改进之前进行更改。好的观点。你认为第一次访问内存时出现的页面错误可以解释这一差异吗?我不知道Windows的情况,但在Linux上,内存是有效分配的n第一次访问已完成。您的猜测完全正确!这两个括号现在提供了完全相同的性能。很好。@Alexandre:是的,如果没有分配物理内存,那么第一次访问将导致页面错误。操作系统将通过分配页面(数千,取决于平台的页面大小)来处理此问题;它可能还必须用零来初始化它们。这将需要相当长的时间。我也不知道Windows,但我有一个模糊的想法,它或多或少做着相同的事情。