kizzx2 kizzx2 - 1 month ago 6
C++ Question

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

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 be not so:

Here's some test results:

UseArray completed in 2.619 seconds
UseVector completed in 9.284 seconds
UseVectorPushBack completed in 14.669 seconds
The whole thing completed in 26.591 seconds


That's about 3 - 4 times slower! Doesn't really justify for the "
vector
may be slower for a few nanosecs" comments.

And the code I used:

#include <cstdlib>
#include <vector>

#include <iostream>
#include <string>

#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/microsec_time_clock.hpp>

class TestTimer
{
public:
TestTimer(const std::string & name) : name(name),
start(boost::date_time::microsec_clock<boost::posix_time::ptime>::local_time())
{
}

~TestTimer()
{
using namespace std;
using namespace boost;

posix_time::ptime now(date_time::microsec_clock<posix_time::ptime>::local_time());
posix_time::time_duration d = now - start;

cout << name << " completed in " << d.total_milliseconds() / 1000.0 <<
" seconds" << endl;
}

private:
std::string name;
boost::posix_time::ptime start;
};

struct Pixel
{
Pixel()
{
}

Pixel(unsigned char r, unsigned char g, unsigned char b) : r(r), g(g), b(b)
{
}

unsigned char r, g, b;
};

void UseVector()
{
TestTimer t("UseVector");

for(int i = 0; i < 1000; ++i)
{
int dimension = 999;

std::vector<Pixel> pixels;
pixels.resize(dimension * dimension);

for(int i = 0; i < dimension * dimension; ++i)
{
pixels[i].r = 255;
pixels[i].g = 0;
pixels[i].b = 0;
}
}
}

void UseVectorPushBack()
{
TestTimer t("UseVectorPushBack");

for(int i = 0; i < 1000; ++i)
{
int dimension = 999;

std::vector<Pixel> pixels;
pixels.reserve(dimension * dimension);

for(int i = 0; i < dimension * dimension; ++i)
pixels.push_back(Pixel(255, 0, 0));
}
}

void UseArray()
{
TestTimer t("UseArray");

for(int i = 0; i < 1000; ++i)
{
int dimension = 999;

Pixel * pixels = (Pixel *)malloc(sizeof(Pixel) * dimension * dimension);

for(int i = 0 ; i < dimension * dimension; ++i)
{
pixels[i].r = 255;
pixels[i].g = 0;
pixels[i].b = 0;
}

free(pixels);
}
}

int main()
{
TestTimer t1("The whole thing");

UseArray();
UseVector();
UseVectorPushBack();

return 0;
}


Am I doing it wrong or something? Or have I just busted this performance myth?

I'm using Release mode in Visual Studio 2005.




In Visual C++,
#define _SECURE_SCL 0
reduces
UseVector
by half (bringing it down to 4 seconds). This is really huge, IMO.

Answer

Using the following:

g++ -O3 Time.cpp -I <MyBoost>
./a.out
UseArray completed in 2.196 seconds
UseVector completed in 4.412 seconds
UseVectorPushBack completed in 8.017 seconds
The whole thing completed in 14.626 seconds

So array is twice as quick as vector.

But after looking at the code in more detail this is expected; as you run across the vector twice and the array only once. Note: when you resize() the vector you are not only allocating the memory but also running through the vector and calling the constructor on each member.

Re-Arranging the code slightly so that the vector only initializes each object once:

 std::vector<Pixel>  pixels(dimensions * dimensions, Pixel(255,0,0));

Now doing the same timing again:

g++ -O3 Time.cpp -I <MyBoost>
./a.out
UseVector completed in 2.216 seconds

The vector now performance only slightly worse than the array. IMO this difference is insignificant and could be caused by a whole bunch of things not associated with the test.

I would also take into account that you are not correctly initializing/Destroying the Pixel object in the UseArrray() method as neither constructor/destructor is not called (this may not be an issue for this simple class but anything slightly more complex (ie with pointers or members with pointers) will cause problems.