Range-for-loops and std::vector

2020-01-29 07:20发布

问题:

Why does this code work

std::vector<int> intVector(10);
for(auto& i : intVector)
    std::cout << i;

And this doesn't?

std::vector<bool> boolVector(10);
for(auto& i : boolVector)
    std::cout << i;

In the latter case, I get an error

error: invalid initialization of non-const reference of type ‘std::_Bit_reference&’ from an rvalue of type ‘std::_Bit_iterator::reference {aka std::_Bit_reference}’

for(auto& i : boolVector)

回答1:

Because std::vector<bool> is not a container !

std::vector<T>'s iterators usually dereference to a T&, which you can bind to your own auto&.

std::vector<bool>, however, packs its bools together inside integers, so you need a proxy to do the bit-masking when accessing them. Thus, its iterators return a Proxy.
And since the returned Proxy is an prvalue (a temporary), it cannot bind to an lvalue reference such as auto&.

The solution : use auto&&, which will correctly collapse into an lvalue reference if given one, or bind and maintain the temporary alive if it's given a proxy.



回答2:

std::vector<bool> does not obey the standard container rules.

In particular, its operator[] does not return bool&.

The loop in the invalid code

#include <vector>
#include <iostream>

int main() {
  std::vector<bool> boolVector(10);
  for (auto& i: boolVector)
      std::cout << i;
}

can be rewritten in any of three ways to iterate through the values:

  1. (read-only)

    for (auto i: boolVector)
        std::cout << i;
    
  2. (read-only, possibly inefficient)

    for (auto const& i: boolVector)  
        std::cout << i;
    
  3. (read/write)

    for (auto&& i: boolVector)
        std::cout << i;
    

The choice between the first and last is down to whether you need to modify the values in the vector, or just to read them.



回答3:

vector<bool> is (usually) specialized explicitly to store each bool in a single bit, reducing the storage costs from one byte per value to one byte per eight values. No processor I know of offhand is bit addressable, so it's impossible to store a reference to the values in the vector<bool>. You need to use plain auto, not auto& for the iteration value i.