C++
标准库可以分为两部分:
标准函数库: 这个库是由通用的、独立的、不属于任何类的函数组成的。函数库继承自C
语言。面向对象类库: 这个库是类及其相关函数的集合。
C++
标准库包含了所有的C
标准库,为了支持类型安全,做了一定的添加和修改。
标准函数库
标准函数库分为以下几类:
输入/输出 I/O字符串和字符处理数学时间、日期和本地化动态分配其他宽字符函数
面向对象类库
标准的C++
面向对象类库定义了大量支持一些常见操作的类,比如输入/输出 I/O、字符串处理、数值处理。面向对象类库包含以下内容:
标准的 C++ I/O 类String 类数值类STL 容器类STL 算法STL 函数对象STL 迭代器STL 分配器本地化库异常处理类杂项支持库
简单地说,标准模板库(STL
)是一组模板类和函数,向程序员提供了:
用于存储信息的容器;用于访问容器存储的信息的迭代器;用于操作容器内容的算法。
1. STL 容器
容器是用于存储数据的STL
类,STL
提供了两种类型的容器类:
顺序容器;关联容器。
另外,STL
还提供了被称为容器适配器(Container Adapter)的类,它们是顺序容器和关联容器的变种,包含的功能有限,用于满足特殊的需求。
1.1 顺序容器
顾名思义,顺序容器按顺序存储数据,如数组和列表。顺序容器具有插入速度快但查找操作相对较慢的特征。
STL
顺序容器如下所示。
std::vector
:操作与动态数组一样,在最后插入数据;可将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.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 新增的。
1.3 容器适配器
容器适配器(Container Adapter)是顺序容器和关联容器的变种,其功能有限,用于满足特定的需求。主要的适配器类如下所示。
std::stack
:以LIFO
(后进先出)的方式存储元素,让您能够在栈顶插入(压入)和删除(弹出)元素。std::queue
:以FIFO
(先进先出)的方式存储元素,让您能够删除最先插入的元素。std::priority_queue
:以特定顺序存储元素,因为优先级最高的元素总是位于队列开头。
2. STL 迭代器
最简单的迭代器是指针。给定一个指向数组中的第一个元素的指针,可递增该指针使其指向下一个元素,还可直接对当前位置的元素进行操作。
STL
中的迭代器是模板类,从某种程度上说,它们是泛型指针。这些模板类让程序员能够对STL
容器进行操作。注意,操作也可以是以模板函数的方式提供的STL
算法,迭代器是一座桥梁,让这些模板函数能够以一致而无缝的方式处理容器,而容器是模板类。
STL
提供的迭代器分两大类。
输入迭代器:通过对输入迭代器解除引用,它将引用对象,而对象可能位于集合中。最严格的输入迭代器确保只能以只读的方式访问对象。
输出迭代器:输出迭代器让程序员对集合执行写入操作。最严格的输出迭代器确保只能执行写入操作。
上述两种基本迭代器可进一步分为三类。
前向迭代器:这是输入迭代器和输出迭代器的一种细化,它允许输入与输出。前向迭代器可以是const
的,只能读取它指向的对象;也可以改变对象,即可读写对象。前向迭代器通常用于单向链表。双向迭代器:这是前向迭代器的一种细化,可对其执行递减操作,从而向后移动。双向迭代器通常用于双向链表。随机访问迭代器:这是对双向迭代器的一种细化,可将其加减一个偏移量,还可将两个迭代器相减以得到集合中两个元素的相对距离。随机访问迭代器通常用于数组。
3. STL 算法
查找、排序和反转等都是标准的编程需求,不应让程序员重复实现这样的功能。因此STL
以STL
算法的方式提供这些函数,通过结合使用这些函数和迭代器,程序员可对容器执行一些最常见的操作。
最常用的STL
算法如下所示。
std::find
:在集合中查找值。std::find_if
:根据用户指定的谓词在集合中查找值。std::reverse
:反转集合中元素的排列顺序。std::remove_if
:根据用户定义的谓词将元素从集合中删除。std::transform
:使用用户定义的变换函数对容器中的元素进行变换。
这些算法都是std
命名空间中的模板函数,要使用它们,必须包含标准头文件<algorithm>
。
4. 迭代器在容器和算法之间交互
下面程序使用了STL
顺序容器std::vector
(它类似于动态数组)来存储一些整数,再使用std::find
算法在集合中查找一个整数。请注意迭代器是如何在这两者之间搭建桥梁的。
#include <iostream>#include <vector>#include <algorithm>using namespace std;int main (){// A dynamic array of integersvector <int> intArray;// Insert sample integers into the arrayintArray.push_back (50);intArray.push_back (2991);intArray.push_back (23);intArray.push_back (9999);cout << "The contents of the vector are: " << endl;// Walk the vector and read values using an iteratorvector <int>::iterator arrIterator = intArray.begin ();while (arrIterator != intArray.end ()){// Write the value to the screencout << *arrIterator << endl;// Increment the iterator to access the next element++ arrIterator;}// Find an element (say 2991) using the 'find' algorithmvector <int>::iterator elFound = find (intArray.begin () , intArray.end (), 2991);// Check if value was foundif (elFound != intArray.end ()){// Determine position of element using std::distanceint elPos = distance (intArray.begin (), elFound);cout << "Value "<< *elFound;cout << " found in the vector at position: " << elPos << endl;}return 0;}
输出结果:
The contents of the vector are: 502991239999Value 2991 found in the vector at position: 1
上述代码演示了如何使用迭代器遍历向量。迭代器是一个接口,将算法(find
)连接到其要操作的数据所属的容器(如vector
)。
第 20 行声明了迭代器对象arrIterator
,并将其初始化为指向容器开头,即vector
的成员函数begin()
返回的值。
第 22~29 行演示了如何在循环中使用该迭代器遍历并显示vector
包含的元素,这与显示静态数组的内容极其相似。迭代器的用法在所有STL
容器中都相同。
所有容器都提供了begin()
函数和end()
函数,其中前者指向第一个元素,后者指向容器中最后一个元素的后面。这就是第 22 行的while
循环在end()
前面而不是end()
处结束的原因。
第 32 行演示了如何使用find
在vector
中查找值。find
操作的结果也是一个迭代器,通过将该迭代器与容器末尾进行比较,可判断find
是否成功,如第 36 行所示。如果找到了元素,便可对该迭代器解除引用(就像对指针解除引用一样)以显示该元素。
算法distance
计算找到的元素的所处位置的偏移量。上述代码所有的vector
都替换为deque
,代码仍能通过编译并完美地运行。这表明迭代器让您能够轻松地使用算法和容器。
5. STL 容器类特点
6. STL 字符串类
STL
提供了一个专门为操纵字符串而设计的模板类:std::basic_string<T>
,该模板类的两个常用具体化如下所示。
std::string
:基于char
的std::basic_string
具体化,用于操纵简单字符串。std::wstring
:基于wchar_t
的std::basic_string
具体化,用于操纵宽字符串,通常用于存储支持各种语言中符号的Unicode
字符。