If you know a bit of modern C++ you will have use the std::vector<T> container a lot of times without even wondering what type you specify to instantiate the container. This is fine for every case except for on specific one, std::vector<bool>.

If you go to the std::vector specification you will find that there is only one specification which is std::vector<bool>. That’s because the bool type specification is implemented outside the standard std::vector<T> container. The reason for this could be pretty obvious and logic for you but it could also be a headache for others who try to use it.

As you may know one bool has the size of 1 byte in the C++ standard. This may make us think why we should use 8 bits when we can know if a bool is true or false just with 1 bit of information, if it’s either 1 = true or 0 = false. Well, that’s exactly what the C++ commitee thought back in the days and decided to use only 1 bit to represent the value in the container, in this way the can store up to 8 values just in 1 byte of memory which means 8 more values than using a standard boolean.

And with that decision is when the problems come. As you may know, a reference is just a memory adress to the beginning of a specific data, which means that you can point to the start of something and increase this position byte by byte.

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vector_int{1, 2};
    
    std::cout << &vector_int[0]; // 0x1e06eb0
    std::cout << &vector_int[1]; // 0x1e06eb4
}

As you can see the offset between the first and the second integer is 4 bytes because that is the size of an int in C++ standard. Now lets try the same with std::vector<bool>.

#include <vector>
#include <iostream>

int main() {
    std::vector<bool> vector_bool{true, false};
    
    std::cout << &vector_bool[0]; // error: taking address of rvalue.
}

The error the compiler give us can be easily understandable by checking out std::vector<bool> specification.

  • Exposes class std::vector<bool>::reference as a method of accessing individual bits. In particular, objects of this class are returned by operator[] by value.

And for the same reason you can’t take values by reference using base-ranged loops which are implemented based on begin() and end().

#include <vector>
#include <iostream>

int main() {
    std::vector<bool> vector_bool{false, true};
    std::vector<int> vector_int{1, 2, 3};

    for (int& i : vector_int) {
        // OK.
    }

    for (bool& b : vector_bool) {
        // error: cannot bind non-const lvalue reference of type 'bool&' to an rvalue of type 'bool'
    }
   
}

Finally, to show the final evidence about the difference between std::vector<T> and std::vector<bool> we can see their sizes in bytes.

int main() {
    std::cout << sizeof(std::vector<int>);   // 24 bytes.
    std::cout << sizeof(std::vector<bool>);  // 40 bytes.
}
Categories: ArticleC++

2 Comments

Mario · July 20, 2021 at 14:03

Hola amigo no entendi la ultima parte, puede explicar el significado de sizeof sobre std::vector ?? no es una instancia concreta, sino el sizeof sobre una clase no?
Es decir instanciar un objeto de vector bool te costaria como minimo 40 bytes?
Un saludo y gracias camarada

    RubenRubioM · July 20, 2021 at 16:59

    Es el tamaño que ocuparía una instancia de esa clase, por ejemplo:

    struct S {
    S() = default;
    int x;
    int z;
    int w;
    };

    int main()
    {
    std::cout << sizeof(S); // 4 bytes * 3 ints = 12 bytes. }

Leave a Reply

Your email address will not be published.