vector<T>标准库模版类应该是绝大多数c++程序员使用频率比较高的一个类了。不过vector<bool>也许就不那么被程序员所了解。关于vector<bool>不尝试研究一番,一般还不太容易知道其中蕴含的问题。

首先得明确一点,那就是vector<bool>是vector<T>的特化版。这个特化版本要解决的问题就是存储容量的问题。

To optimize space allocation, a specialization of vector for bool elements is provided.

所以,它一般来说是以位的方式来存储bool的值。从这里我们可以看出,如果使用位来提升空间效率可能引出的问题就是时间效率了。因为俺们的计算机地址是以字节为单位的。这里可以看一个例子:

int main()
{
clock_t t1, t2, t3;
vector<bool> vb;
vector<int> vi;
vector<char> vc; t1 = clock();
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
vb.push_back(true);
}
}
t1 = clock() - t1; t2 = clock();
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
vi.push_back();
}
}
t2 = clock() - t2; t3 = clock();
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
vc.push_back('a');
}
}
t3 = clock() - t3; cout << "'vector<bool>::push_back(true)' 1000000 times cost: " << t1 << endl;
cout << "'vector<int>::push_back(1)' 1000000 times cost: " << t2 << endl;
cout << "'vector<char>::push_back('a')' 1000000 times cost: " << t3 << endl; t1 = clock();
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
bool b = vb[j + * i];
}
}
t1 = clock() - t1; t2 = clock();
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
int b = vi[j + * i];
}
}
t2 = clock() - t2; t3 = clock();
for (int i = ; i < ; ++i)
{
for (int j = ; j < ; ++j)
{
char b = vc[j + * i];
}
}
t3 = clock() - t3; cout << "'vector<bool>::operator[]' 1000000 times cost: " << t1 << endl;
cout << "'vector<int>::operator[]' 1000000 times cost: " << t2 << endl;
cout << "'vector<char>::operator[]' 1000000 times cost: " << t3 << endl; return ;
}

我的机器上的输出结果是:

vector<bool>的耗时要比vector<T>多至少40倍以上!不简单。。。

这里我们只是简单得验证了下vector<bool>的特别之处。接下来再从标准文档中看看有什么特别之处:

There is no requirement that the data be stored as a contiguous allocation of bool values. A space-optimized representation of bits is recommended instead.

所以,vector<bool>就没要求说底层的存储必须是连续的空间。这也就从一个方面说明了我们上面的例子有如此之大的差异一个原因。

另外,事实上vetor<bool>只是从暴露出来的API上看,是一个容器。而事实上他丫的就不是个容器。

这还得先简单说说C++的容器。我们知道vector<T>(T不是bool)是一个顺序容器(Sequence container)。因此他满足C++标准中关于容器的标准。比方说下面这条:

Expression Return type
X::reference lvalue of T

简单说vector<int>::reference至少必须是一个int。而vector<bool>则不是这样的。vector<bool>::reference是一个可以和bool兼容的代理数据结构。

最简单的验证这一点的例子就是:

template <typename T>
void func(vector<T>& v)
{
T& ref = v[0];
}

上面这段代码你在vc2012或者g++4.6.1上,传递一个vector<bool>对象,都不能通过编译。g++给出的编译错误就相当清晰了:

vectorbool.cpp: In function ‘void func(std::vector<T>&) [with T = bool']’:

vectorbool.cpp:18:11:    instantiated from here

vectorbool.cpp:9:17: error: invalid initialization of non-const reference of type ’bool&’ from an rvalue of type ‘std::vector<bool>::reference {aka std::_Bit_reference}’

operator[]返回的reference是一个右值就不是个左值(lvalue of T)。

所以,vector<bool>就不是个容器。

总结一下:

  1. vector<bool>可能存在性能问题
  2. 它并不是个真正的容器,因此在模版代码上的使用可能会有问题。如果问题能发生在编译器那还好,换到运行期,还真有点麻烦(vector<bool>::operator[] misbehavior?)。

Reference:

  1. What You Should Know about vector<bool>
  2. The Fate of vector<bool> in C++09
  3. vector<bool>: More Problems, Better Solutions

更新(2017年3月27日)

vector<bool>因为其特殊性,所以在使用Range-based for loop时,要小心。比方说:

 int main()
{
std::vector<bool> bools { false, false, false } // change value (expected to see bools are not changed).
for (auto b : bools)
{
b = true;
} // print bools
for (auto const & b : bools)
{
std::cout << std::boolalpha << b << std::endl;
} return ;
}

我们会发现bools里的value全部变成true了。真是头大。

说一说vector<bool>的更多相关文章

  1. std::vector<bool>中的坑

    http://www.cplusplus.com/reference/vector/vector/?kw=vector C++中,vector<bool>为了达到节省内存的目的,专门做了特 ...

  2. std::vector<bool> 在 auto 推断下的返回值是 bool & 引用

    转自: https://www.cnblogs.com/hustxujinkang/p/5218148.html //////////// std::vector<bool> featur ...

  3. STL:vector<bool> 和bitset

    今天某个地方要用到很多位标记于是想着可以用下bitset,不过发现居然是编译时确定空间的,不能动态分配.那就只能用vector来代替一下了,不过发现居然有vector<bool>这个特化模 ...

  4. Effective STL 学习笔记 Item 18: 慎用 vector<bool>

    vector<bool> 看起来像是一个存放布尔变量的容器,但是其实本身其实并不是一个容器,它里面存放的对象也不是布尔变量,这一点在 GCC 源码中 vector<bool> ...

  5. C++ std::vector<bool>

    std::vector template < class T, class Alloc = allocator<T> > class vector; // generic te ...

  6. 《条目十八》避免使用vector<bool>

    <条目十八>避免使用vector 先说结论: 一是:vector<bool>不是标准容器,因为标准容器的对于T *p = &c[0];必须是可编译的. 二是:vecto ...

  7. 避免使用vector&lt;bool&gt;

     作为一个STL容器,vector<bool>仅仅有两点不正确. 首先.它不是一个STL容器. 其次,它并不存储bool.除此之外.一切正常. 一个对象要成为容器,就必须满足C++标准 ...

  8. vector容器

    vector<int> ivec; vector<Sales_item> Sales_vec; 和其他变量定义一样,定义 vector 对象要指定类型和一个变量的列表.上 面的 ...

  9. C++小知识之Vector排序

    // sort algorithm example #include <iostream>     // std::cout #include <algorithm>    / ...

随机推荐

  1. 很不错的jQuery学习资料和实例

    这些都是学习Jquery很不错的资料,整理了一下,分享给大家. 希望能对大家的学习有帮助. 帕兰 Noupe带来的51个最佳jQuery教程和实例, 向大家介绍了jQuery的一些基本概念和使用的相关 ...

  2. property attribute: assign, strong, weak, unsafe_unretain and copy

    assign:用于“纯量类型”(如CGFloat 或 NSInteger等): strong:用于“对象类型”,定义了一种“拥有关系”(owning relationship),为这种属性设置新值时, ...

  3. 基于tp框架实现的递归城市查询

    控制器层: 接下来就是模型层: 如果说你的数据量庞大到致使apache或者nginx停止运行,有两点原因: 1.代码耦合性不高,代码有错误: 2.php.ini里面有一个memory_limit的这个 ...

  4. 如何使官方提供的AppRTCDemo 运行在自己搭建的server(官方提供的apprtc)上(官方的server源码)

    原文转自 http://stackoverflow.com/questions/21085261/apprtcdemo-with-local-server-works-between-browsers ...

  5. js遍历数组的错误方法

    for (var index in myArray) { // don't actually do this console.log(myArray[index]); } 缺点: 数组的索引值inde ...

  6. Count Color(线段树+位运算 POJ2777)

    Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 39917 Accepted: 12037 Descrip ...

  7. 151102SQL语句

    $condition = array($pk=>array('in',explode(',',$id)));//??? $this->model->where($condition) ...

  8. System & Runtime &Math

    package com.shushine.framework.第七章Java标准类库;/** * * <p> * 描述该类情况 {@link 代表跟谁有关系} * </p> * ...

  9. ShareSDK第三方登录代码

    - (IBAction)YYSJBut:(UIButton *)sender{    if (sender.tag == 7)    {        [self AuthLogin:SSDKPlat ...

  10. 单元测试:查找list[]中的最大值

     原始代码如下: int Largest(int list[], int length) { int i,max; for(i = 0; i < (length – 1); i ++ ) { i ...