C++ 疑难杂症一——奇怪的 vector<bool>

问题描述

在增强 for 循环中,遍历 vector<int>vector<bool>,并通过引用修改数组中的每个元素:

遍历 int 的代码不会报错:

std::vector<std::vector<int>> arr{{1, 0, 0}, {0, 0, 0}};
for (auto & rows : arr) {
    for (int & tmp : rows) {
        tmp = 0;
    }
}

然而,如果将 int 替换为 bool

std::vector<std::vector<bool>> arr{{1, 0, 0}, {0, 0, 0}};
for (auto & rows : arr) {
    for (bool & tmp : rows) {	// 报错:类型不必配!bool & tmp 为左值引用,rows 返回的类型为 std::__bit_iterator<std::vector<bool>>
        tmp = 0;
    }
}

报错信息

=> 则会报错:Non-const lvalue reference to type 'bool' cannot bind to a temporary of type 'std::__bit_iterator<std::vector<bool>, false, 0>::reference' (aka 'std::__bit_reference<std::vector<bool>, true>')

=> 即使将非常量引用,改为常量引用,也会有警告:Clang-Tidy: The type of the loop variable 'tmp' is different from the one returned by the iterator and generates an implicit conversion; you can either change the type to the matching one ('const std::__bit_iterator<std::vector<bool>, false, 0>::reference &' (aka 'const std::__bit_reference<std::vector<bool>, true> &') but 'const auto&' is always a valid option) or remove the reference to make it explicit that you are creating a new value


分析

上述报错表明语句在将一个临时对象绑定到一个非常(const)值的左值引用上,导致了类型不匹配。具体地,临时对象为 rows,类型为 vector<bool> &,而 tmp 则为 bool 类型的非常量左值引用。问题来了:为什么 vector<int> & 绑定到 int 类型的非常量左值引用可以,换做 bool 就报错了呢?

仔细看报错信息,临时对象的类型为 std::__bit_iterator<std::vector<bool>>,即 vector<bool>::iterator 返回的不是真正的 bool,而是 std::__bit_iterator<std::vector<bool>>

文档记载

实际上,en.cppreference.com 中对这点有记录:

bool 类型本身的大小随实现而定,但很多编译器中都是一个字节:

https://en.cppreference.com/w/cpp/language/types#:~:text=standard%20integer%20types.-,Boolean%20type,-bool%20%E2%80%94%20type%2C%20capable

然而,vector<bool> 从节省空间的角度(同时如果实现恰当的话还会加速执行时间),将数组中的每个元素实现成 1bit,而不是一个 sizeof(bool) bytes

https://en.cppreference.com/w/cpp/container/vector_bool#:~:text=Allocator%3E%3B-,std%3A%3Avector%3Cbool%3E,bytes.,-std%3A%3Avector

其他

对于这一点,其他地方也都有相关的描述,有的将这种实现视为一种双刃剑,有的认为这是一种错误:

解决方案

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值