C ++数组与向量

时间:2009-12-22 11:21:30

标签: c++ visual-studio arrays vector

使用C ++向量时,花费的时间是718毫秒, 当我使用Array时,时间几乎是0毫秒。

为什么这么大的性能差异?

int _tmain(int argc, _TCHAR* argv[])
{
const int size = 10000; 
clock_t start, end; 
start = clock();
vector<int> v(size*size); 
for(int i = 0; i < size; i++)
{  
    for(int j = 0; j < size; j++)
    {   
        v[i*size+j] = 1;  
    } 
} 
end = clock();
cout<< (end - start)
    <<" milliseconds."<<endl; // 718 milliseconds

int f = 0;
start = clock(); 
int arr[size*size]; 
for(int i = 0; i < size; i++)
{  
    for(int j = 0; j < size; j++)
    {   
        arr[i*size+j] = 1;  
    } 
} 
end = clock();
cout<< ( end - start)
    <<" milliseconds."<<endl; // 0 milliseconds
return 0;
}

8 个答案:

答案 0 :(得分:21)

您的数组arr在堆栈上分配,即编译器在编译时计算了必要的空间。在该方法的开头,编译器将插入一个汇编语句,如

sub esp, 10000*10000*sizeof(int)

表示堆栈指针(esp)减少10000 * 10000 * sizeof(int)个字节,以便为10000 2 整数的数组腾出空间。这个操作几乎是即时的。

向量是堆分配的,堆分配要贵得多。当向量分配所需的内存时,它必须向操作系统询问一块连续的内存块,操作系统必须执行大量工作才能找到这块内存。

正如安德烈亚斯在评论中所说,你所有的时间都花在这一行上:

vector<int> v(size*size); 

访问循环内的向量与数组一样快。

有关其他概述,请参阅例如

修改

在关于性能优化和编译器设置的所有评论之后,我今天早上做了一些测量。我必须设置size=3000所以我用大约十分之一的原始条目进行测量。所有测量均在2.66 GHz Xeon上进行:

  1. 使用Visual Studio 2008中的调试设置(无优化,运行时检查和调试运行时),矢量测试花费了920 ms,而阵列测试则为0 ms。

    vector::operator[]中花费了98,48%的总时间,即确实花费在运行时检查上的时间。

  2. 完全优化后,矢量测试需要56 ms(带有原始条目数的十分之一),而阵列则为0 ms。

    vector ctor需要61.72%的应用程序运行时间。

  3. 所以我猜每个人都是正确的,这取决于所使用的编译器设置。 OP的时序表明优化的构建或STL没有运行时检查。

    与往常一样,士气是:配置文件优先,优化第二。

答案 1 :(得分:9)

如果您使用Microsoft编译器进行编译,为了使其公平比较,您需要通过定义_SECURE_SCL = 0和_HAS_ITERATOR_DEBUGGING = 0来关闭迭代器安全检查和迭代器调试。

其次,您使用的构造函数将每个向量值初始化为零,并且在填充之前您不会将数组memset为零。所以你要遍历矢量两次。

尝试:

vector<int> v; 
v.reserve(size*size);

答案 2 :(得分:3)

将作业更改为例如。 arr[i*size+j] = i*j,或其他一些非常量表达式。我认为编译器会优化整个循环,因为从不使用赋值,或者用一些预先计算的值替换数组,因此循环甚至不会被执行而且你得到0毫秒。

将1更改为i*j后,i获取向量和数组的相同时序,除非将-O1标志传递给gcc,然后在两种情况下都得到0毫秒。

所以,首先,仔细检查你的循环是否实际执行。

答案 3 :(得分:3)

为了得到公平的比较,我认为以下内容应该是合适的:

#include <sys/time.h>
#include <vector>
#include <iostream>
#include <algorithm>
#include <numeric>


int main()
{
  static size_t const size = 7e6;

  timeval start, end;
  int sum;

  gettimeofday(&start, 0);
  {
    std::vector<int> v(size, 1);
    sum = std::accumulate(v.begin(), v.end(), 0);
  }
  gettimeofday(&end, 0);

  std::cout << "= vector =" << std::endl
        << "(" << end.tv_sec - start.tv_sec
        << " s, " << end.tv_usec - start.tv_usec
        << " us)" << std::endl
        << "sum = " << sum << std::endl << std::endl;

  gettimeofday(&start, 0);
  int * const arr =  new int[size];
  std::fill(arr, arr + size, 1);
  sum = std::accumulate(arr, arr + size, 0);
  delete [] arr;
  gettimeofday(&end, 0);

  std::cout << "= Simple array =" << std::endl
        << "(" << end.tv_sec - start.tv_sec
        << " s, " << end.tv_usec - start.tv_usec
        << " us)" << std::endl
        << "sum = " << sum << std::endl << std::endl;
}

在这两种情况下,都会执行动态分配和释放,以及对元素的访问。

在我的Linux机上:

$ g++ -O2 foo.cpp 
$ ./a.out 
= vector =
(0 s, 21085 us)
sum = 7000000

= Simple array =
(0 s, 21148 us)
sum = 7000000

std::vector<>和数组案例都具有可比性。关键是如果您的代码结构合理,std::vector<>可以和简单数组一样快。


在相关的说明中,关闭优化会在这种情况下产生巨大的差异:

$ g++ foo.cpp 
$ ./a.out 
= vector =
(0 s, 120357 us)
sum = 7000000

= Simple array =
(0 s, 60569 us)
sum = 7000000

像Neil和jalf这样的人做出的许多优化断言是完全正确的。

HTH!

编辑:更正了代码以强制矢量销毁包含在时间测量中。

答案 4 :(得分:2)

您可能正在使用VC ++,在这种情况下,默认情况下,标准库组件在运行时执行许多检查(例如,索引是否在范围内)。可以通过将某些宏定义为0(我认为_SECURE_SCL)来关闭这些检查。

另一件事是我甚至无法按原样运行你的代码:自动数组对于堆栈来说太大了。当我将它设为全局时,那么使用MingW 3.5,我得到的时间是向量627 ms,数组26875 ms(!!),这表明这个大小的数组确实存在很大的问题。

对于这个特殊的操作(填充值1),你可以使用vector的构造函数:

std::vector<int> v(size * size, 1);

和数组的填充算法:

std::fill(arr, arr + size * size, 1);

答案 5 :(得分:1)

两件事。一,运算符[]对于向量来说要慢得多。二,当你一次添加一个元素时,大多数实现中的向量都会表现得很奇怪。我并不仅仅意味着它会分配更多的内存,但它有时会做一些真正奇怪的事情。

第一个是主要问题。对于仅仅百万字节,甚至重新分配内存十几次不应该花费很长时间(它不会在每个添加的元素上执行)。

在我的实验中,预分配并没有太大改变其缓慢程度。当内容是实际的对象时,如果你尝试做一些简单的事情,比如排序它,它基本上就会停止。

结论,不要将stl或mfc向量用于任何大型或计算量较大的载体。它们执行得很慢/很慢并导致大量内存碎片。

答案 6 :(得分:0)

当你声明数组时,它存在于堆栈中(或静态内存区域),它非常快,但不能增加它的大小。

当您声明向量时,它会分配动态内存,它不是那么快,但在内存分配方面更灵活,因此您可以更改大小而不是将其标注为最大大小。

答案 7 :(得分:0)

在分析代码时,请确保您正在比较类似的东西。

vector<int> v(size*size); 

初始化向量中的每个元素

int arr[size*size]; 

没有。尝试

int arr[size * size];
memset( arr, 0, size * size );

再次测量......