26 Beginner The Hundred
The Container of Lies
the copy that kept in touch
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {0, 0, 0};
std::vector<bool> flags = {false, false, false};
auto n = nums[0]; // copy the first number
n = 42; // change the copy
auto f = flags[0]; // copy the first flag
f = true; // change the copy
std::cout << std::boolalpha;
std::cout << "n = " << n << ", nums[0] = " << nums[0] << '\n';
std::cout << "f = " << f << ", flags[0] = " << flags[0] << '\n';
}
Run it. What does it print?
Answer
The int copy behaved. The bool "copy" flipped a bit inside the vector.
Why¶
std::vector<bool> is a mandated specialization that packs eight elements into each
byte — and you cannot form a bool& to a single bit. So its operator[] returns a
small proxy object, std::vector<bool>::reference, that remembers which bit it stands
for. auto dutifully deduces that proxy type, so f is no bool: assigning to it
calls the proxy's operator=, which writes straight through to the vector. n really
is a detached int, because nums[0] returns int& and auto drops references. The
proxy is also why you can't point into the vector — build with g++ -DSHOW_BUG ... and
the hidden line bool* p = &flags[0]; fails with
error: cannot convert ‘std::vector<bool>::reference*’ to ‘bool*’. No warning flag
catches the write-through; the code is perfectly legal.
The fix¶
Name the type and you get a genuine copy:
When you need honest, addressable booleans, use std::vector<char> or
std::deque<bool> — neither one is specialized.
Takeaway: std::vector<bool>[i] hands you a write-through proxy, not a bool& —
spell out bool when you want a copy.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo