为什么在我的机器上std::vector的分配和释放比动态数组慢



我的印象是std::vector只是动态数组的一个薄薄的包装器,它们的性能应该相当。在互联网上搜索和stackoverflow本身也给出了相同的答案。然而,当我自己测试它时,我发现了巨大的差异。代码如下。我尝试了VC++2012(发布版本)和带有优化标志-O2的MinGW。

new、malloc和calloc的时间大约为0.005秒,而std::vector在这两个编译器上都需要0.9秒。是std::vector本身就很慢,还是我的代码有一些严重的缺陷?

#define _SCL_SECURE 0
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <time.h>
struct timer
{
    clock_t start;
    timer()
    {
        start=clock();
    }
    ~timer()
    {
        double t=static_cast<double>(clock()-start)/CLOCKS_PER_SEC;
        printf("%lfn", t);
    }
};
int main()
{
    const size_t len=(1<<28);   
    {
        timer t;
        int *d=new int[len];
        printf("%dn",d[len-1]);//prevent compiler from optimizing away 
                                //useless allocation and deallocation
        delete[] d;
    }
    {
        timer t;
        int *d=(int *)malloc(len*sizeof(int));
        printf("%dn", d[len-1]);
        free(d);
    }
    {
        timer t;
        std::vector<int> d(len);
        printf("%dn", d[len-1]);
    }
    {
        timer t;
        int *d=(int *)calloc(len, sizeof(int));
        printf("%dn", d[len-1]);
        free(d);
    }
    return 0;
}

编辑1

根据建议,我测试了创建动态阵列的其他方法

  • new:0.005
  • malloc:0.005
  • calloc:0.005
  • malloc+memset:1.244
  • vector(len):1.231
  • vector(len, 0):1.234
  • vector.reserve(len):0.005

因此,真正的罪犯是零初始化,而不是分配或释放。这意味着,如果需要一个零初始化的数组,即使vector有一个默认初始化所有元素的构造函数,它也不是最佳选择。

此外,这不仅仅是我突然想到的事情。我为一堂课做的最后一个项目是根据所花的时间进行评分的,为了异常安全,我使用了几个vector来分配一个巨大的内存缓冲区,而不是new,因为我们的教科书鼓励使用STL。直到今天我才意识到我因此丢了一些分。悲伤的一天。

编辑2

今天我在Ubuntu 13.04 x64上尝试了Clang 3.2,std::vector不再需要那么长时间来初始化。事实上,矢量现在是最快的!也许这毕竟是一个编译器优化问题,而不是std::vector设计中固有的问题。

我相信这是由于std::vector的分配调用了每个元素上的复制构造函数,而malloc只返回未初始化的内存。

std::vector<int> x(100); 

实际上与相同

std::vector<int> y(100, int()); 

请参阅有关std::vector构造函数的文档http://en.cppreference.com/w/cpp/container/vector/vector

我经常会做这样的事情:

std::vector<int> x; 
x.reserve(100);
// Insert items into x via x.push_back()
printf("%dn",d[len-1]);//prevent compiler from optimizing away 

此行从未初始化的对象中读取。它没有阻止编译器优化事情,而是给它做任何它想做的事情的余地(即程序的行为是未定义的)。

让我们假设我们以某种方式解决了这个问题,程序的行为现在已经定义好了(也许我们添加了一行初始化d[len-1])。

std::vector<int> d(len);

此行初始化值为0的len对象。另一行没有:

int *d=new int[len];

唯一一个导致len对象值为0的行是:

int *d=(int *)calloc(len, sizeof(int));

从与分配和解除分配性能相关的基准中,您可以得出的唯一结论是,该基准不适合得出与分配和取消分配性能有关的结论。

相关内容

  • 没有找到相关文章

最新更新