简体   繁体   中英

operator |= on std::vector<bool>

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 ?

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 (ie 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[] (ie std::vector<bool>::reference ) cannot simply be a bool & . Internally, it would probably contain a reference to the underlying type (eg a unsigned char ) and information to track what bit it actually affects. This would make all op = operators ( += , -= , |= , etc) somewhat expensive operations (eg bit fiddling) on the underlying type.

The designers of std::vector<bool> would then have faced a choice between

  1. specify that std::vector<bool>::reference support all the op = and hear continual complaints about runtime inefficiency from programmers who use those operators

  2. Don'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 .

您为什么不只执行以下操作?

enable[0] = enable[0] | true;

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM