一.容器
第1条:慎重选择容器类型
C++提供了几种不同的容器供选择,他们之间各有差别,简单回顾一下:
- 标准STL序列容器:vector、string、deque、list。
- 标准STL关联容器:set、multiset、map、multimap。
- 非标准序列容器:slist(单向链表)、rope(”重型”string)。
- 非标准关联容器:hash_set、hash_multiset、hash_map、hash_multimap(均基于哈希表)。
- vector<char>作为string的替代:第13条中讲述了何种条件下这种替代的意义。
- vector作为标准关联容器的替代:第23条中阐述了,有时vector在运行时间和空间上都要优于标准关联容器。
- 几种标准的非STL容器:数组、bitset、valarray、stack、queue、priority_queue,第16条中提及了一种“数组优于STL容器”的情形;第18条中解释了bitset比vector<bool>要好;另外,数组也可被用于STL算法,这是因为指针可被用作数组的迭代器。
如上,可做出的选择是很多的,这意味着我们在做出选择的时候要考虑多种因素,C++标准对“如何在vector、deque和list中做出选择”提供的建议:
vector、list和deque为程序员提供了不同的复杂性,使用时要对此做出权衡。vector是默认应使用的序列类型;当需要频繁地在序列中间做插入和删除操作时,应使用list;当大多数插入与删除操作发生在序列的头部和尾部时,deque是应考虑的数据结构。
以上建议如果是从算法复杂性考虑的话,是恰当的,但除此之外应考虑的还有很多。
STL有一种分类方法,这是对连续内存容器和基于节点的容器的区分:
- 连续内存容器:把它的元素存放在一块或多块(动态分配的)内存中,每块内存中存有多个元素,当有新元素插入或已有元素被删除时,同一内存块中的其他元素要向前或向后移动,为新元素让出空间,或者填充被删除的元素。这种移动影响到效率(参见第5条,第14条)和异常安全性。标准的连续内存容器有vector、string和deque,非标准的rope也是一个连续内存容器。
- 基于节点的容器:每一个(动态分配的)内存块中只存放一个元素。容器元素的插入或删除值只影响到指向节点的指针,而不影响节点本身的内容,所以当有插入或删除操作时,元素值不需要移动。表示链表的容器,如list和slist,是基于节点的;所有标准的关联容器也是如此(通常实现方式为平衡树);非标准的哈希容器使用不同的基于节点的实现,第25条可看到这一点。
有了以上术语基础,以下是选择容器时应考虑的一些问题: