标准模板库简介
简单地说,标准模板库(STL)是一组模板类和函数,向程序员提供了:
- 用于存储信息的容器;
- 用于访问容器存储的信息的迭代器;
- 用于操作容器内容的算法。
1.1 STL容器
容器是用于存储数据的STL类,STL提供了两种类型的容器类:
- 顺序容器;
- 关联容器。
另外,STL还提供了被称为容器适配器(Container Adapter)的类,它们是顺序容器和关联容器的变种,包含的功能有限,用于满足特殊的需求。
1.1.1 顺序容器
顾名思义,顺序容器按顺序存储数据,如数组和列表。顺序容器具有插入速度快但查找操作相对较慢的特征。
顺序容器如下所示。
- std::vector:操作与动态数组一样,在最后插入数据;
- std::deque:与std::vector类型,但运行在开头插入或删除元素;
- std::list:操作与双向链表一样。可将它视为链条,对象被连接在一起,可在任何位置添加或删除对象;
- std::forward_list:类似于std::list,但是单向链表,只能沿一个方向遍历。
STL vector类与数组类似,允许随机访问元素,即可使用下标运算符([])指定元素在vector中的位置(索引),从而直接访问或操作元素。另外,STL vector是动态数组,因此能够根据应用程序在运行阶段的需求自动调整长度。为保留数组能够根据位置随机访问元素的特征,大多数STL vector实现都将所有元素存储在连续的存储单元中,因此需要调整长度的vector通常会降低应用程序的性能,这取决于它包含的对象类型。
可将STL list类视为普通链表的STL实现。虽然list中的元素不能像STL vector中的元素那样随机访问,但list可使用不连续的内存块组织元素,因此它不像std::vector那样需要给内部数组重新分配内存,进而导致内存问题。
1.1.2 关联容器
关联容器按指定的顺序存储数据,就像词典一样。这将降低插入数据的速度,但在查询方面有很大的优势。
STL提供的关联容器如下所示。
- std::set:存储各不相同的值,在插入时进行排序;容器的复杂度为对数;
- std::unordered_set:存储各不相同的值,在插入时进行排序;容器的复杂度为常数。这种容器是C++11新增的。
- std::map:存储键-值对,并根据唯一的键排序;容器的复杂度为对数;
- std::unordered_map:存储键-值对,并根据唯一的键排序;容器的复杂度为对数。这种容器是C++11新增的。
- std::multiset:与set类似,但允许存储多个值相同的项,即值不需要是唯一的;
- std::unordered_multiset:与unordered_set类似,但允许存储多个值相同的项,即值不需要是唯一的。这种容器是C++11新增的。
- std::multimap:与map类型,但不要求键是唯一的。
- std::unordered_multimap:与unordered_map类似,但不要求键是唯一的。这种容器是C++11新增的。
有些STL实现也支持关联容器hash_set, hash_multiset, hash_map和hash_multimap,它们与标准支持的unordered_*容器类型。在有些情况下,hash_*和unordered_*容器有更好的元素搜索性能,因为其元素访问时间为常量。
1.1.3 容器适配器
容器适配器是顺序容器和关联容器的变种,其功能有限,用于满足特定的需求。
主要的适配器类如下所示。
- std::stack:以LIFO(后进先出)的方式存储元素,能够在栈顶插入和删除元素;
- std::queue:以FIFO的方式存储元素,能够删除最先插入的元素;
- std::priority_queue:以特定顺序存储元素,优先级最高的元素总是位于队列开头。
1.2 STL迭代器
最简单的迭代器是指针。给定一个指向数组中的第一个元素的指针,可递增该指针使其指向下一个元素,还可直接对当前位置的元素进行操作。
STL中的迭代器是模板类,从某种程度上说,它们是泛型指针。这些模板类让程序员能够对STL容器进行操作。注意,操作也可以是以模板函数的方式提供的STL算法,迭代器是一座桥梁,让这些模板函数能够以一致而无缝的方式处理容器,而容器是模板类。
STL提供的迭代器分两大类。
- 输入迭代器:通过对输入迭代器解除引用,它将引用对象,而对象可能位于集合中。最严格的输入迭代器确保只能以只读的方式访问对象。
- 输出迭代器:输出迭代器让程序员对集合执行写入操作。最严格的输出迭代器确保只能执行写入操作。
上述两种基本迭代可进一步分为三类。
- 前向迭代器:这是输入迭代器和输出迭代器的一种细化,它允许输入与输出。前向迭代器可以 是 const 的,只能读取它指向的对象;也可以改变对象,即可读写对象。前向迭代器通常用于 单向链表。
- 双向迭代器:这是前向迭代器的一种细化,可对其执行递减操作,从而向后移动。双向迭代器通常用于双向链表。
- 随机访问迭代器:这是对双向迭代器的一种细化,可将其加减一个偏移量,还可将两个迭代器 相减以得到集合中两个元素的相对距离。随机访问迭代器通常用于数组。
1.3 STL算法
查找、排序和反转都是标准的编程需求,STL以STL算法的方式提供了这些函数,通过结合使用这些函数和迭代器,程序员可对容器执行一些最常见的操作。
最常用的STL算法如下所示。
- std::find:在集合中查找值。
- std::find_if:根据用户指定的谓词在集合中查找值。
- std:reverse:反转集合中元素的排列顺序。
- std::remove_if:根据用户定义的谓词将元素从集合中删除。
- std::transform:使用用户定义的变换函数对容器中的元素进行变换。
这些算法都是std命令空间中的模板函数,要使用它们,必须包含标准头文件<algorithm>。
1.4 选择正确的容器
可能有多种STL容器能够满足应用程序的需求,这时必须做出选择,这种选择很重要,因为错误的选择将导致性能问题和可扩展性瓶颈。
1.5 STL字符串类
STL提供了一个专门为操纵字符串而设计的模板类:std::basic_string<T>,该模板类的两个常用具体化如下所示。
- std::string:基于char的std::basic_string具体化,用于操纵简单字符串。
- std::wstring:基于wchar_t的std::basic_string具体化,用于操作宽字符串,通常用于存储支持各种语言中符号的Unicode字符。