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.
}