说一说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> / ...
随机推荐
- 如何在page_load方法判断是服务器端控件引发的page_load方法
动态获取单击的服务器端控件的id值 private string getPostBackControlName() { Control control=null; s ...
- Android_按两次返回键退出程序和长按返回键退出程序
以上两个功能主要是参考了一下博客的: http://blog.csdn.net/chenshijun0101/article/details/7682210 http://blog.csdn.net/ ...
- 一个带标号的CSS文章列表写法
<title>CSS文章列表</title> <style type="text/css"> *{margin:0;padding:0;list ...
- Android 程序崩溃后的处理
在应用发布以后,由于安卓机型的千差万别 ,可能会出现各种各样的问题,这时候如果我们可以将这些信息收集起来,并进行修改就很不错了.下面就来讨论一下怎么处理程序崩溃以后,错误信息的手机. Java中已经提 ...
- Dynamics AX 2012 R2 安装额外的AOS
众所周知,AX系统分为三层:Client,Application Server,Database Server. 我们添加额外的Application Server主要是出于以下两个原因: 使用多台服 ...
- SVN merge的主干,分支的相互合并操作
本文只研究了 在本地如何进行主干,分支的相互合并 的操作:从主干到分支,从分支到主干. 本地客户端工具是tortoisesvn 测试用例. 1.本地添加test文件夹 在test文件夹下分别建立tru ...
- 【转】 #1451 - Cannot delete or update a parent row: a foreign key constraint fails 问题的解决办法
转载地址:http://blog.csdn.net/donglynn/article/details/17056099 错误 SQL 查询: DELETE FROM `zmax_lang` WHERE ...
- Linux phpbb论坛的安装(英文版)
1:建立文件夹
- Python正则表达式学习摘要及资料
摘要 在正则表达式中,如果直接给出字符,就是精确匹配. {m,n}? 对于前一个字符重复 m 到 n 次,并且取尽可能少的情况 在字符串'aaaaaa'中,a{2,4} 会匹配 4 个 a,但 a{2 ...
- URLClassLoader类
URLClassLoader类 1.URLClassLoader类也是ClassLoader类的实现类,它的功能非常强大,他可以从本地文件系统中获取二进制文本来加载类,也可以从远程主机获取二进制文件来 ...