说一说vector<bool>
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>就不是个容器。
总结一下:
- vector<bool>可能存在性能问题
- 它并不是个真正的容器,因此在模版代码上的使用可能会有问题。如果问题能发生在编译器那还好,换到运行期,还真有点麻烦(vector<bool>::operator[] misbehavior?)。
Reference:
- What You Should Know about vector<bool>
- The Fate of vector<bool> in C++09
- 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>的更多相关文章
- std::vector<bool>中的坑
http://www.cplusplus.com/reference/vector/vector/?kw=vector C++中,vector<bool>为了达到节省内存的目的,专门做了特 ...
- std::vector<bool> 在 auto 推断下的返回值是 bool & 引用
转自: https://www.cnblogs.com/hustxujinkang/p/5218148.html //////////// std::vector<bool> featur ...
- STL:vector<bool> 和bitset
今天某个地方要用到很多位标记于是想着可以用下bitset,不过发现居然是编译时确定空间的,不能动态分配.那就只能用vector来代替一下了,不过发现居然有vector<bool>这个特化模 ...
- Effective STL 学习笔记 Item 18: 慎用 vector<bool>
vector<bool> 看起来像是一个存放布尔变量的容器,但是其实本身其实并不是一个容器,它里面存放的对象也不是布尔变量,这一点在 GCC 源码中 vector<bool> ...
- C++ std::vector<bool>
std::vector template < class T, class Alloc = allocator<T> > class vector; // generic te ...
- 《条目十八》避免使用vector<bool>
<条目十八>避免使用vector 先说结论: 一是:vector<bool>不是标准容器,因为标准容器的对于T *p = &c[0];必须是可编译的. 二是:vecto ...
- 避免使用vector<bool>
作为一个STL容器,vector<bool>仅仅有两点不正确. 首先.它不是一个STL容器. 其次,它并不存储bool.除此之外.一切正常. 一个对象要成为容器,就必须满足C++标准 ...
- vector容器
vector<int> ivec; vector<Sales_item> Sales_vec; 和其他变量定义一样,定义 vector 对象要指定类型和一个变量的列表.上 面的 ...
- C++小知识之Vector排序
// sort algorithm example #include <iostream> // std::cout #include <algorithm> / ...
随机推荐
- 机器学习实战-K-nearest neighbors 算法的优缺点
K临近算法是基于实例的学习,使用算法的时候我们必须要有接近分类结果的实例训练样本数据. 优点:精度高,对异常值不敏感 缺点: 时间复杂度和空间复杂度比较大.(如果训练样本数据集比较大,需要大量的空间来 ...
- MVC中return File(byte[],"image/jpeg")输入图片不清晰
MVC中需要输入图片的时候有一个便捷的方法,return File(byte[],"image/jpeg"); 但是这样处理的图片很不清晰(特别是要进行缩放,DrawImage,D ...
- mysql常用操作语句(转)
mysql -u root -p mysql -h localhost -u root -p database_name 2.列出数据库: show databases; 3.选择数据库: use ...
- php 全角半角转换
<?phpheader("Content-type: text/html; charset=utf-8");// 第一个参数:传入要转换的字符串// 第二个参数:取0,半角转 ...
- 【Tarjan】+【SPFA】APIO2009 Atm
一.算法介绍 tarjan——求解有向图强连通分量.这个算法在本人的一篇blog中有介绍,这里就不赘述了.贴上介绍tarjan的的blog链接:http://www.cnblogs.com/Maki- ...
- python matplotlib 中文显示参数设置
python matplotlib 中文显示参数设置 方法一:每次编写代码时进行参数设置 #coding:utf-8import matplotlib.pyplot as pltplt.rcParam ...
- Unity3D之协程(Coroutines & Yield )
在Unity中StartCoroutine/yield return这个模式到底是怎么应用的? 比如你要一个方法进行一个比较耗时的复杂运算~同时又想让脚本流畅的进行其他操作而不是卡在那里等该方法执行完 ...
- GZFramwork快速开发框架演练之会员系统(四)添加商品管理
1.1:创建表结构 新建三张商品关联的表,表模型如下: 创建SQL语句略 1.2:生成表Model(生成方法见上一节) 1.3:生成tb_ProductType的单结构界面然后添加到项目中 1.4:修 ...
- 运用EasyUI中datagrid读取数据库数据实现分页
1dao层 package com.hanqi.dao; import java.util.ArrayList; import java.util.List; import org.hibernate ...
- 18.ssh远程双向无密码登陆
#ssh远程双向无密码登陆 需求:在192.168.10.100执行ssh 192.168.20.205不需要输入密码直接跳转到205机器 #在192.168.10.100执行命令,我这里使用root ...