Is std::vector so much slower than plain arrays?

后端 未结 22 2380
南方客
南方客 2020-11-22 12:00

I\'ve always thought it\'s the general wisdom that std::vector is \"implemented as an array,\" blah blah blah. Today I went down and tested it, and it seems to

22条回答
  •  不思量自难忘°
    2020-11-22 12:17

    To be fair, you cannot compare a C++ implementation to a C implementation, as I would call your malloc version. malloc does not create objects - it only allocates raw memory. That you then treat that memory as objects without calling the constructor is poor C++ (possibly invalid - I'll leave that to the language lawyers).

    That said, simply changing the malloc to new Pixel[dimensions*dimensions] and free to delete [] pixels does not make much difference with the simple implementation of Pixel that you have. Here's the results on my box (E6600, 64-bit):

    UseArray completed in 0.269 seconds
    UseVector completed in 1.665 seconds
    UseVectorPushBack completed in 7.309 seconds
    The whole thing completed in 9.244 seconds
    

    But with a slight change, the tables turn:

    Pixel.h

    struct Pixel
    {
        Pixel();
        Pixel(unsigned char r, unsigned char g, unsigned char b);
    
        unsigned char r, g, b;
    };
    

    Pixel.cc

    #include "Pixel.h"
    
    Pixel::Pixel() {}
    Pixel::Pixel(unsigned char r, unsigned char g, unsigned char b) 
      : r(r), g(g), b(b) {}
    

    main.cc

    #include "Pixel.h"
    [rest of test harness without class Pixel]
    [UseArray now uses new/delete not malloc/free]
    

    Compiled this way:

    $ g++ -O3 -c -o Pixel.o Pixel.cc
    $ g++ -O3 -c -o main.o main.cc
    $ g++ -o main main.o Pixel.o
    

    we get very different results:

    UseArray completed in 2.78 seconds
    UseVector completed in 1.651 seconds
    UseVectorPushBack completed in 7.826 seconds
    The whole thing completed in 12.258 seconds
    

    With a non-inlined constructor for Pixel, std::vector now beats a raw array.

    It would appear that the complexity of allocation through std::vector and std:allocator is too much to be optimised as effectively as a simple new Pixel[n]. However, we can see that the problem is simply with the allocation not the vector access by tweaking a couple of the test functions to create the vector/array once by moving it outside the loop:

    void UseVector()
    {
        TestTimer t("UseVector");
    
        int dimension = 999;
        std::vector pixels;
        pixels.resize(dimension * dimension);
    
        for(int i = 0; i < 1000; ++i)
        {
            for(int i = 0; i < dimension * dimension; ++i)
            {
                pixels[i].r = 255;
                pixels[i].g = 0;
                pixels[i].b = 0;
            }
        }
    }
    

    and

    void UseArray()
    {
        TestTimer t("UseArray");
    
        int dimension = 999;
        Pixel * pixels = new Pixel[dimension * dimension];
    
        for(int i = 0; i < 1000; ++i)
        {
            for(int i = 0 ; i < dimension * dimension; ++i)
            {
                pixels[i].r = 255;
                pixels[i].g = 0;
                pixels[i].b = 0;
            }
        }
        delete [] pixels;
    }
    

    We get these results now:

    UseArray completed in 0.254 seconds
    UseVector completed in 0.249 seconds
    UseVectorPushBack completed in 7.298 seconds
    The whole thing completed in 7.802 seconds
    

    What we can learn from this is that std::vector is comparable to a raw array for access, but if you need to create and delete the vector/array many times, creating a complex object will be more time consuming that creating a simple array when the element's constructor is not inlined. I don't think that this is very surprising.

提交回复
热议问题