说一说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> / ...
随机推荐
- 鸟哥的linux私房菜学习记录之系统设定工具与硬件检测
这部分没啥用,就不记录了,关于服务器的在服务器篇
- JS逗号运算符的用法详解
逗号运算符的用法详解 注意: 一.由于目前正在功读JavaScript技术,所以这里拿JavaScript为例.你可以自己在PHP中试试. 二.JavaScript语法比较复杂,因此拿JavaScri ...
- tcp粘包,udp丢包
TCP是面向流的, 流, 要说明就像河水一样, 只要有水, 就会一直流向低处, 不会间断. TCP为了提高传输效率, 发送数据的时候, 并不是直接发送数据到网路, 而是先暂存到系统缓冲, 超过时间或者 ...
- HBase Mac OSX 安装笔记
本次测试安装的机器为Mac Book Pro, 系统为 OS X 10.9.4.hbase版本0.98.6.1. 使用Java版本为Oracle的JDK 1.6.0_65. 1. 下载安装 hbase ...
- CentOS 7下关于systemd的一些唠叨话二:systemd服务脚本的编写
CentOS 7继承了RHEL 7的新的特性,例如强大的systemd,而systemd的使用也使得以往系统服务的/etc/init.d的启动脚本的方式就此改变,也大幅提高了系统服务的运行效率.但服务 ...
- 微信 xml 转 Map
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; xml + ...
- [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序处理并发
这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十篇:为ASP.NET MVC应用程序 ...
- shell awk入门
本文参考自 http://www.cnblogs.com/zhuyp1015/archive/2012/07/11/2586985.html awk:好用的数据处理工具 awk 也是一个非常棒的数据处 ...
- 深入浅出设计模式——解释器模式(Interpreter Pattern)
模式动机 如果在系统中某一特定类型的问题发生的频率很高,此时可以考虑将这些问题的实例表述为一个语言中的句子,因此可以构建一个解释器,该解释器通过解释这些句子来解决这些问题.解释器模式描述了如何构成一个 ...
- 跨站脚本 XSS<一:防御方法>
1. 过滤特殊字符 避免XSS的方法之一主要是将用户所提供的内容进行过滤,许多语言都有提供对HTML的过滤: PHP的htmlentities()或是htmlspecialchars(). Pytho ...