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. Oracle常用日期函数

    常用的时间格式掩码如下:掩码元素       含义YYYY           四位数年份 (如:2005)     yearYY             二位数年份(如  05) Q         ...

  2. VS2010 支持 CSS3

    在安装Standards Update for VS2010 SP1后,VS2010中没有CSS3.0问题,以下是我的解决方法 1.首先去官网下载 CSS 3 Intellisense Schema ...

  3. Android安装失败 Installation error code: -110

    在系统开发过程中,开发的app管理器,发现怎么安装都是失败. 详细的查看了log发现. I/ActivityManager(  899): START {dat=file:///mnt/sdcard/ ...

  4. php strrpos()与strripos()函数不同之处在哪里呢

    strripos() 函数 定义和用法strripos() 函数查找字符串在另一个字符串中最后一次出现的位置.如果成功,则返回位置,否则返回 false.语法strrpos(string,find,s ...

  5. 回传数据startActivityForResult()

    1.调用者Activity01开启新的界面选用startActivityForResult(intent,requestCode);在Activity01中Intent intent=new Inte ...

  6. CSS 盒子模型概述

    一.简介   CSS 盒子模型(元素框)由元素内容(content).内边距(padding).边框(border).外边距(margin)组成.     盒子模型,最里面的部分是实际内容:直接包围内 ...

  7. log4j2的使用

    预备知识 日志级别:log4j默认六个级别,即trace.debug.info.warn.error.fatal ,对应意味着该消息为追踪.调试.普通信息.警告.错误.严重错误.可以根据需要子定义其他 ...

  8. 《BI那点儿事》数据流转换——查找转换

    查找转换通过联接输入列中的数据和引用数据集中的列来执行查找.是完全匹配查找.在源表中查找与字表能关联的所有源表记录.准备数据.源表 T_QualMoisture_Middle_Detail字典表 T_ ...

  9. vs2010打包(带数据库)图文详解

    最近刚刚打包发布了用VS2010开发的一个收费系统,借此讲一讲打包过程,供大家参考. 首先打开已经完成的工程,如图: 下面开始制作安装程序包. 第一步:[文件]——[新建]——[项目]——安装项目. ...

  10. 线程池ExecutorService和完成服务CompletionService的使用获取线程的返回结果

    package com.suning.ecif.admin.app.impl.temp; import java.util.ArrayList;import java.util.Collection; ...