C++ Exploring The Darker Corners

 TRAP 1:
 How NOT to preallocate space for std::vector

It might have already come to your attention that efficient use of std::vector requires that we reserve space in advance. Of course, in many cases, we do not know the exact size of our vector (otherwise we would have opted for the fixed-size std::array). But often we do have some information about its initial size, at least in terms of orders of magnitude.

This is where things might get a bit tricky. Novices tend to get this wrong and afterward get surprised by the contents of their data structures. Look at the snippet below. You might think that the snippet below gives you the vector with elements 0,1,2 but you will be mistaken:

#include <iostream>
#include <vector>

// C++17
int main(){
    // WRONG !
    auto v = std::vector<int>(3); 
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    for(auto e : v)
        std::cout << e << ' '; // 0 0 0 0 1 2
}

std::vector<int> (3) gives you a vector of 3 elements - all of them with a default integer value 0. After that, it pushes 0, 1 and 2 to the end of the vector. The resulting vector is thus 0 0 0 0 1 2. So, instead of reserving space for 3 elements, we called the std::vector's constructor with count default-inserted instances (3 default integer instances) and pushed back some more elements.

To correct the mistake we need to remove the count from the constructor and instead call std::vector::reserve() as demonstrated in the snippet below:

#include <iostream>
#include <vector>

// C++17
int main(){
    // CORRECT !
    auto v = std::vector<int>{}; 
    v.reserve(3);
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    for(auto e : v)
        std::cout << e << ' '; // 0 1 2
}