Item 18 of Scott Meyers's book Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library says to avoid vector <bool>
as it's not an STL container and it doesn't really hold bools.
The following code:
vector <bool> v;
bool *pb =&v[0];
will not compile, violating requirement of STL containers.
Error:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector<T>::operator []
return type is supposed to be T&, but why it's a special case for vector<bool>
?
What does vector<bool>
really consist of?
The Item further says:
deque<bool> v; // is a STL container and it really contains bools
Can this be used as an alternative to vector<bool>
?
Can anyone please explain this?
This comes from http://www.cplusplus.com/reference/vector/vector-bool/
Many consider the
vector<bool>
specialization to be a mistake.In a paper "Deprecating Vestigial Library Parts in C++17"
There is a proposal to Reconsider vector Partial Specialization.
For space-optimization reasons, the C++ standard (as far back as C++98) explicitly calls out
vector<bool>
as a special standard container where each bool uses only one bit of space rather than one byte as a normal bool would (implementing a kind of "dynamic bitset"). In exchange for this optimization it doesn't offer all the capabilities and interface of a normal standard container.In this case, since you can't take the address of a bit within a byte, things such as
operator[]
can't return abool&
but instead return a proxy object that allows to manipulate the particular bit in question. Since this proxy object is not abool&
, you can't assign its address to abool*
like you could with the result of such an operator call on a "normal" container. In turn this means thatbool *pb =&v[0];
isn't valid code.On the other hand
deque
doesn't have any such specialization called out so each bool takes a byte and you can take the address of the value return fromoperator[]
.Finally note that the MS standard library implementation is (arguably) suboptimal in that it uses a small chunk size for deques, which means that using deque as a substitute isn't always the right answer.
The problems is that
vector<bool>
returns a proxy reference object instead of a true reference, so that C++98 style codebool * p = &v[0];
won't compile. However, modern C++11 withauto p = &v[0];
can be made to compile ifoperator&
also returns a proxy pointer object. Howard Hinnant has written a blog post detailing the algorithmic improvements when using such proxy references and pointers.Scott Meyers has a long Item 30 in More Effective C++ about proxy classes. You can come a long way to almost mimic the builtin types: for any given type
T
, a pair of proxies (e.g.reference_proxy<T>
anditerator_proxy<T>
) can be made mutually consistent in the sense thatreference_proxy<T>::operator&()
anditerator_proxy<T>::operator*()
are each other's inverse.However, at some point one needs to map the proxy objects back to behave like
T*
orT&
. For iterator proxies, one can overloadoperator->()
and access the templateT
's interface without reimplementing all the functionality. However, for reference proxies, you would need to overloadoperator.()
, and that is not allowed in current C++ (although Sebastian Redl presented such a proposal on BoostCon 2013). You can make a verbose work-around like a.get()
member inside the reference proxy, or implement all ofT
's interface inside the reference (this is what is done forvector<bool>::bit_reference
), but this will either lose the builtin syntax or introduce user-defined conversions that do not have builtin semantics for type conversions (you can have at most one user-defined conversion per argument).TL;DR: no
vector<bool>
is not a container because the Standard requires a real reference, but it can be made to behave almost like a container, at least much closer with C++11 (auto) than in C++98.vector<bool>
contains boolean values in compressed form using only one bit for value (and not 8 how bool[] arrays do). It is not possible to return a reference to a bit in c++, so there is a special helper type, "bit reference", which provides you a interface to some bit in memory and allows you to use standard operators and casts.Look at how it is implemented. the STL builds vastly on templates and therefore the headers do contain the code they do.
for instance look at the stdc++ implementation here.
also interesting even though not an stl conforming bit vector is the llvm::BitVector from here.
the essence of the
llvm::BitVector
is a nested class calledreference
and suitable operator overloading to make theBitVector
behaves similar tovector
with some limitations. The code below is a simplified interface to show how BitVector hides a class calledreference
to make the real implementation almost behave like a real array of bool without using 1 byte for each value.this code here has the nice properties:
This code actually has a flaw, try to run:
will not work because
assert( (&b[5] - &b[3]) == (5 - 3) );
will fail (withinllvm::BitVector
)this is the very simple llvm version.
std::vector<bool>
has also working iterators in it. thus the callfor(auto i = b.begin(), e = b.end(); i != e; ++i)
will work. and alsostd::vector<bool>::const_iterator
.However there are still limitations in
std::vector<bool>
that makes it behave differently in some cases.