问题
The following code doesn't compile
#include <vector>
int main()
{
std::vector<bool> enable(10);
enable[0] |= true;
return 0;
}
giving the error
no match for ‘operator|=’ (operand types are ‘std::vector<bool>::reference {aka std::_Bit_reference}’ and ‘bool’)
In my real life code I have a bit field with values I want to |=
with the result of a function.
There are easy way to express the same idea, but is there any good reason for such an operator not to be available ?
回答1:
The main reason would be that std::vector<bool>
is special, and its specification specifically permits an implementation to minimise memory usage.
For vectors of anything other than bool
, the reference type can actually be a true reference (i.e. std::vector<int>::reference
can actually be an int &
) - usually directly referencing an element of the vector itself. So it makes sense for the reference type to support all operations that the underlying type can. This works because vector<int>
effectively manages a contiguous array of int
internally. The same goes for all types other than bool
.
However, to minimise memory usage, a std::vector<bool>
may not (in fact probably will not) work internally with an actual array of bool
. Instead it might use some packed data structure, such as an array of unsigned char
internally, where each unsigned char
is a bitfield containing 8
bits. So a vector<bool>
of length 800 would actually manage an array of 100
unsigned char, and the memory it consumes would be 100
bytes (assuming no over-allocation). If the vector<bool>
actually contained an array of 800
bool
, its memory usage would be a minimum of 800
bytes (since sizeof(bool) must be at least 1
, by definition).
To permit such memory optimisation by implementers of vector<bool>
, the return type of vector<bool>::operator[]
(i.e. std::vector<bool>::reference
) cannot simply be a bool &
. Internally, it would probably contain a reference to the underlying type (e.g. a unsigned char
) and information to track what bit it actually affects. This would make all op=
operators (+=
, -=
, |=
, etc) somewhat expensive operations (e.g. bit fiddling) on the underlying type.
The designers of std::vector<bool>
would then have faced a choice between
specify that
std::vector<bool>::reference
support all the op=
and hear continual complaints about runtime inefficiency from programmers who use those operatorsDon't support those op
=
and field complaints from programmers who think such things are okay ("cleaner code", etc) even though they will be inefficient.
It appears the designers of std::vector<bool>
opted for option 2. A consequence is that the only assignment operators supported by std::vector<bool>::reference
are the stock standard operator=()
(with operands either of type reference
, or of type bool
) not any of the op=
. The advantage of this choice is that programmers get a compilation error if trying to do something which is actually a poor choice in practice.
After all, although bool
supports all the op=
using them doesn't achieve much anyway. For example, some_bool |= true
has the same net effect as some_bool = true
.
回答2:
Why don't you just do the following?
enable[0] = enable[0] | true;
回答3:
You should be able to make one yourself pretty easily. Something like:
std::vector<bool>::reference& operator |= (std::vector<bool>::reference& a, bool b)
{
if (b)
a = true;
return a;
}
Alternatively, std::bitset is a good fit.
回答4:
Short and sweet answer: std::vector<bool>
should be avoided. Use vector<wchar>
instead. You actually get a container back in which the bools are packed in bits, which gives different behaviour from other vectors, slow code and no-one cares a bout memory anyway. I guess by now no-one likes this anymore, but turning back the clock would break too much code...
来源:https://stackoverflow.com/questions/28882959/operator-on-stdvectorbool