vector: reserve with care

vectors, std::vector, are contiguous-memory sequential dynamic containers. That means if the vector has to grow then it will re-allocate the required memory to hold elements and then copy these over in the new memory. That is one of the reasons that for any type to be contained in vector must define default, copy constructors and assignment operator. However there is a way to work around this reallocation problem if we know before hand how much the vector is going to grow. The method reserve does the job:

1
2
3
4
5
6
std::vector< int > vec;
vec.reserve(10);
for(int idx = 0; idx < 10 ; ++idx )
{
    vec.push_back(idx);
}

This contrived example shows how to use the reserve method, but in real life we generally don’t reserve the new containers, but there may be a container that is passed in as one of the arguments and you are trying to fill-it up:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
std::vector<int> vec;
vec.reserve(10);
for(int idx = 0; idx < 10 ; ++idx )
{
    vec.push_back(idx);
}

vec.reserve(10);
for(int idx = 0; idx < 10 ; ++idx )
{
    vec.push_back(idx);
}

This looks quite intuitive, however it is flawed when reserving the memory. vec.reserve(10); does not imply reserve 10 more slots it means just reserve 10 slots. What that means is if your container already has 12 elements vec.reserve(10); becomes no-op, cause the container already has more memory allocated than what you required. If your intention was to resize the vector then there is an explicit method named resize.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
std::vector<int> vec;
vec.reserve(10);
for( int idx = 0; idx < 10; ++idx )
{
    vec.push_back(idx);
}

vec.reserve(vec.size() + 10);
for( int idx = 0; idx < 10; ++idx )
{
    vec.push_back(idx);
}