vector < bool >: What isn’t can’t be.

vector<bool> doesn’t behave like other STL containers. If you try to obtain a reference to a bool inside the container, you’ll end up with an rvalue. Probably not what you had in mind. Oddly, it IS standard compliant (more on this later). Therefore you can’t say it’s not “standard compliant” container. What it doesn’t follow is the optional sequence container operations format from table 101 in section [sequence.reqmts / 23.2.3]. This table states the format for operator [] to return a reference or a const_reference. Assuming in this case vector<T>, a reference would be a T& and a const_reference a const T&. In the case of vector<bool>, operator[] returns a “reference” which is a class (more on this later). So there you have it. vector<bool> is standards compliant, but doesn’t meet the container requirements.

What vector<bool>::operator[] return: is a value type, of class reference. The type is defined as follows as a nested class within the specialization of the vector template [vector.bool]:

   // bit reference:

   class reference {

      friend class vector;

      reference() noexcept;

   public:

      ~reference();

      operator bool() const noexcept;

      reference& operator=(const bool x) noexcept;

      reference& operator=(const reference& x) noexcept;

      void flip() noexcept; // flips the bit

   };

The standard has this to say about this class: reference is a class that simulates the behavior of references of a single bit in vector<bool>. Notice the operator bool() for implicit conversion to bool. What this means is you you can’t get a bool reference as you would another T type, say ints:

   vector<bool> boolVec(1, true);

   boolVec[0] = false;

   bool& tempBool = boolVec[0]; // ERROR: Not valid C++.

   vector<int> intVec(1, 1);

   intVec[0] = 0;

   int &tempBool = intVec[0]; // Ok, get reference to int.

Basically, by the time operator bool is called, you receive an rvalue. Which means you can’t get a reference to it. All you can do is get a copy of that bool.

So why does the operator[] still modify the vector<bool>? Well, the return type is vector<bool>::reference (not bool). Which means you can do the following:

   vector<bool>::reference rb = boolVector[0]; // Reference to an element.

   Rb = 1; // Modifying the reference.

The standard doesn’t exactly spell out if this is a good idea. However if we use the bool, it’s essentially the same as:

   bool b = rb.operator bool();

Which is now a copy of the underlying bool.

To bring it all together: What we have with vector<bool> is a proxy container. It appears to hold bools, however it actually stores something else as we saw, which is implicitly convertible to bools (like a good proxy). Why it was created is To optimize space allocation. However considering the limitation of not being able to obtain references to the storage type places some restrictions which may not be suitable.

Why is vector<bool> in the standard? Some think it was an experiment which went wrong and somehow stayed in the standard for backwards compatibility. I’ve also read it was meant to be a production quality example of how to create a proxy container (with their known limitations). I can see the value of that argument. A container of objects acting as proxies to a webservice call or other other slow resource has value in the right context.

Final thoughts: The only container as of C++14 to specialize for bools is vector. If you need a container of bools, you may want to consider deque or anything other than vector if the lack of reference is a deal breaker. And if you need to write a container specialization for a proxy type, would be worth giving the section [vector.bool] a read. It’s a short and readable passage.

Leave a Reply

Your email address will not be published. Required fields are marked *