关于c ++:Range-for-loops和std :: vector

Range-for-loops and std::vector<bool>

为什么这个代码有效

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

但事实并非如此?

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

在后一种情况下,我会得到一个错误

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}’

1
for(auto&amp; i : boolVector)


因为std::vector不是一个容器!

std::vector的迭代器通常取消对T&的引用,可以将其绑定到自己的auto&上。

但是,std::vector将其bool打包在整数内,因此访问它们时需要代理来进行位屏蔽。因此,它的迭代器返回一个Proxy。由于返回的Proxy是一个prvalue(临时的),它不能绑定到一个lvalue引用,如auto&

解决方案:使用auto&&,如果给定值,它将正确地折叠为左值引用;如果给定代理,则绑定并保持临时活动。


std::vector不遵守标准集装箱规则。

特别是它的operator[]没有返回bool&

无效代码中的循环

1
2
3
4
5
6
7
8
#include <vector>
#include <iostream>

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

可以通过以下三种方法中的任意一种重写值:

  • (只读)

    1
    2
    for (auto i: boolVector)
        std::cout << i;
  • (只读,可能效率低下)

    1
    2
    for (auto const& i: boolVector)  
        std::cout << i;
  • (读/写)

    1
    2
    for (auto&& i: boolVector)
        std::cout << i;
  • 在第一个和最后一个之间的选择取决于您是需要修改向量中的值,还是仅仅为了读取它们。


    vector通常专门用于将每个bool存储在一个位中,从而将存储成本从每值一个字节减少到每8个值一个字节。目前我所知道的任何处理器都不是位可寻址的,因此不可能存储对vector中值的引用。迭代值i需要使用plain auto,而不是auto&