Effective STL 条款18

原创 2004年02月26日 14:51:00

Item18避免使用vector<bool>
 
做为一个STL容器,vector<bool>有两个问题.第一,它不是一个真正STL容器,第二,它并不保存bool类型.
除此以外,并没有太多东西与本节题目有关(译注,还不够多吗)

一个东西不能成为一个STL容器,只因为会有人说它是一个(译注,:( ).一个东西要成为STL容器,必须满足所有
列于C++标准23.1节的容器要求.在这些要求中,有这样一条:如果C是一个T类型元素容器,并且C支持operator[]
那么以下代码必须能够编译:

T *p = &c[0]; // initialize a T* with the address
       // of whatever operator[] returns

换句话说,如果你使用operator[]来得到Container<T>中的一个T对象,你可以对它取地址从而得到一个指针.
(假设T没有重载opeartor&.译注:原句为This assumes that T hasn't perversely overloaded operators.
从意译)因此,如果vector<bool>可能成为容器,那么,这些代码必须编译通过:

vector<bool> v;
bool *pb = &v[0]; // initialize a bool* with the address of
                  // what vector<bool>::operator[] returns

但是它不能编译.不能的原因是vector<bool>是一个伪容器(pseudo-container),它并不保存真正的bool,而是
打包bool以节省空间.在一个典型的实现中,每一个"bool"保存在"vector"中都是一个"bit",8-bit的一个字节
将保存8个bool.从内部来看,vector<bool>使用了与位域(bitfields)相同的思想来表示需要保存的bool值.

与bool值相似,位域也只有两个值,但有它俩之间有一个重要的不同:可以创建指向真正的bool型的指针,但指
向单独一位的指针却非法.

考虑到指向单独一位的指针非法,这为vector<bool>的设计摆出了难题.因为vector<T>::operator[]的返回值
是T&类型.如果vector<bool>保存真正的bool值,这不成问题.但是因为它没有,vector<bool>::operator[]
(译注:原文为()疑误)不知如何返回一位的引用,并不存在这样的东西.

为了解决它,vector<boo>::operator[]返回一个对象,其行为类似于位的引用,也称为代理对象.(仅使用STL,
你并不需要明白什么是代理.它是一项值得了解的C++技术.关于代理的信息,参考More Effective C++的Item30
还有Gamma等人(就是GoF)的设计模式一书中Proxy章节).深入本质来看,vector<bool>可能类似于这样:

 template <typename Allocator>
 vector<bool, Allocator> {
 public:
 class reference {...}; // class to generate proxies for
    // references to individual bits
 reference operator[](size_type n); // operator[] returns a proxy
 …
 }

现在,这些代码不能编译的原因就很明显了.

vector<bool> v;
bool *pb = &v[0]; // error! the expression on tne right is
    // of type vector<bool>::reference*,
    // not bool*

因为它不能编译,所以vector<boo>不满足STL容器的需要.vector<bool>在标准中,它也满足了大多数STL容器的需要
,但是它还不够好.你写的关STL容器的代码越多,会越深刻地认识到这一点.当一天来到时,我保证,当你会写
出一个模板,它只在可以取得容器元素的地址时才工作.到那时,你将突然明白容器和几乎是一容器之间的区别.

也许你想知道为什么vector<bool>存在于标准中,而它并不是一个容器.答案是与一个贵族失败的实验有关.但让我们
推迟一下讨论,我有一个更紧迫的问题.如果vector<bool>应避免,因为它不是一个容器,那当需要一个vector<bool>时
应使用什么?

标准库提供了两个代替物,它们满足几乎所有需要.第一个是deque<bool>.deque提供几乎所有vector提供的(唯一值得
注意的是reserve和capacity),并且deque<bool>是一个STL容器,它保存真正的bool值.当然,deque底层的内存不连续.
所以不能传递deque<bool>中的数据给一个期望得到bool数组的C API(参见Item 16),但是vector<bool>也不能作这一点
因为没用可移植的方法取得vector<bool>中的数据.(Item16中的技术不能在vector<boo>上编译.因为这种技术依赖于
能够取得容器元素的指针.我提到过vector<bool>中不保存bool值吧?)

第二个vector<bool>的代替物是bitset.bitset不是一个STL容器,但它是C++标准库的一部分.与STL容器不同,它的大小
(元素总数)在编译期固定.因此,它不支持插入和删除元素,近一步,因为它不是一个STL容器,它也不支持iterator.
与vector<bool>类似,它使用一个压缩的表示法,使得每个值只占用一位.它提供vector<bool>的特殊成员函数,还包含
一系列操作位集(collection of bits)的特殊成员函数.如果不在乎没有迭代器和动态大小,那么bitset也许正合你意.

现在我们来讨论那个贵族的失败的实验,正是它将非STL容器的vector<bool>留在了标准库中.我早先提到代码对象在C++
程序设计中十分有用.C++标准委员会的成员当然也意识到了,他们决定开发vector<bool>做为一个演示.它说明STL如何
支持包含通过代理访问元素的容器.一但这个例子出现在标准中,而且它说明得很详细,开发者将有一个参考,来实现自己
的基于代理的容器.

可是,最终他们发现,不可能创建一种基于代理的容器,它满足所有STL容器的需要.因为某种原因,他们失败了,而开发中
的这个例子留在了标准中.也许有人将探寻vector<bool>存在的原因,但现实地说,这不影响什么.重要的是:vector<bool>
不满足STL容器的需要;你最好不要使用它;deque<bool>和bitset是基本能满足你的需要vector<bool>代替品.

effective stl 第19条:理解相等(equality)和等价(equivalence)的区别

#include #include #includeusing namespace std;bool ciStringCompare(const string l, const string r) {...
  • u014110320
  • u014110320
  • 2016年09月20日 23:36
  • 251

Effective STL学习笔记-条款19

条款19 了解相等和等价的区别了解相等和等价的区别例如find函数,或者一个set容器插入一个值得时候都会进行比较。但是它们的行为是不同的,find是通过 operator==,而set::inser...
  • gx864102252
  • gx864102252
  • 2017年08月27日 21:01
  • 105

Effective STL条款17-条款18

条款17:使用交换技巧来修正过剩容量本节条款告诉我们,如果你有一个vector的容器,容器的容量是10000,但是,现在只用了1,那么为了节省内存,我们应该只保留使用的vector容量,多余的容量应该...
  • u011058765
  • u011058765
  • 2016年04月21日 09:10
  • 291

Effective STL 中文版(完整版)

 Winter总算找到《Effective STL》的完整中文版了,奉献给大家。书中作者解释了怎样结合STL组件来在库的设计得到最大的好处。这样的信息允许你对简单、直接的问题开发简单、直接的解决方案,...
  • WinterTree
  • WinterTree
  • 2005年01月16日 01:23
  • 16318

《Effective C++》:条款28-条款29

条款28避免返回handles指向对象内部成分:指的是不能返回对象内部数据/函数的引用、指针等。 条款29为异常安全而努力是值得的:指的是要有异常处理机制,避免发生异常时造成资源泄露等问题。...
  • KangRoger
  • KangRoger
  • 2015年02月19日 19:47
  • 1399

Effective C++ 条款2

尽量以const、enum、inline替换#define首先,大家要明白一个道理。#define是什么,有什么作用。很简单,大家都知道#define实现宏定义,如下代码:#define Flag 1...
  • u011058765
  • u011058765
  • 2015年06月19日 12:06
  • 502

《Effective C++》:条款41-条款42

条款41了解隐式接口和编译期多态 条款42了解typename的双重意义条款
  • KangRoger
  • KangRoger
  • 2015年03月10日 22:13
  • 1250

Effective STL- 熟悉非标准的散列容器(hash 容器)

 条款25:熟悉非标准散列容器STL程序员一般用不了多久就开始惊讶,“vector、list、map,很好,但是散列(hash)表在哪里"?唉,在标准C++库里没有任何散列表。 每个人都同意这是个不幸...
  • bichenggui
  • bichenggui
  • 2009年10月21日 22:21
  • 1914

《Effective C++》:条款44-条款45

条款44将与参数无关的代码抽离templates 条款45运用成员函数模板接受所有兼容类型...
  • KangRoger
  • KangRoger
  • 2015年03月12日 22:01
  • 1513

Effective Modern C++ 条款23 理解std::move和std::forward

Effective Modern C++ 条款23
  • big_yellow_duck
  • big_yellow_duck
  • 2016年08月30日 17:11
  • 1245
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effective STL 条款18
举报原因:
原因补充:

(最多只允许输入30个字)