什么是STL
STL(Standard Template Library,标准模板库)是C++标准库中最核心、最常用的部分。它提供了一套通用的、高效的、可复用的组件,让开发者不需要重复造轮子,就能完成绝大多数数据结构和算法相关的编程任务。
STL诞生于20世纪90年代初,由Alexander Stepanov和Meng Lee在HP实验室开发,后来被纳入C++标准。它的设计哲学是泛型编程(Generic Programming):将算法与数据类型解耦,用模板实现一套代码适配多种类型。
STL的三大组件
STL的核心由三大组件构成,它们紧密配合,形成了一个强大的工具体系。
1. 容器(Containers)
容器是用来存放数据的对象。你可以把它理解为”数据结构”的标准实现。STL的容器按逻辑结构可以分为三大类:
- 序列容器:线性排列的数据,如
vector、list、deque、array、forward_list
- 关联容器:基于键值对的有序数据结构,如
map、set、multimap、multiset
- 无序关联容器:基于哈希表的无序数据结构(C++11引入),如
unordered_map、unordered_set
2. 迭代器(Iterators)
迭代器是连接容器和算法的桥梁。它提供了一种统一的方式来遍历容器中的元素,而不需要关心容器的底层实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <iostream> #include <vector> #include <list>
int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; std::list<int> lst = {10, 20, 30, 40, 50};
std::cout << "vector: "; for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl;
std::cout << "list: "; for (auto it = lst.begin(); it != lst.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl;
std::cout << "range-for: "; for (const auto& x : vec) { std::cout << x << " "; } std::cout << std::endl;
return 0; }
|
迭代器按照功能分为五个类别:
| 类别 |
支持操作 |
典型容器 |
| 输入迭代器 |
只读、单遍递增 |
istream_iterator |
| 输出迭代器 |
只写、单遍递增 |
ostream_iterator |
| 前向迭代器 |
读写、多遍递增 |
forward_list |
| 双向迭代器 |
读写、双向移动 |
list, map, set |
| 随机访问迭代器 |
读写、任意跳跃 |
vector, deque, array |
3. 算法(Algorithms)
STL提供了70多个标准算法,涵盖排序、查找、变换、数值计算等各种操作。算法通过迭代器操作容器中的数据,实现了数据与操作的分离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream> #include <vector> #include <algorithm> #include <numeric>
int main() { std::vector<int> vec = {5, 3, 1, 4, 2};
std::sort(vec.begin(), vec.end());
auto it = std::find(vec.begin(), vec.end(), 3); if (it != vec.end()) { std::cout << "找到元素: " << *it << std::endl; }
int sum = std::accumulate(vec.begin(), vec.end(), 0); std::cout << "总和: " << sum << std::endl;
std::reverse(vec.begin(), vec.end());
for (int x : vec) { std::cout << x << " "; } return 0; }
|
STL头文件概览
使用STL时需要包含对应的头文件。以下是常用头文件一览:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <vector> #include <list> #include <deque> #include <array> #include <forward_list> #include <map> #include <set> #include <unordered_map> #include <unordered_set> #include <stack> #include <queue> #include <string>
#include <algorithm> #include <numeric>
#include <iterator>
#include <functional> #include <memory> #include <utility>
|
基本使用理念
泛型编程思想
STL的核心是泛型编程。以 sort 为例,它不关心排序的是什么类型的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream> #include <algorithm> #include <vector> #include <string>
int main() { std::vector<int> vi = {3, 1, 4, 1, 5}; std::sort(vi.begin(), vi.end());
std::vector<std::string> vs = {"banana", "apple", "cherry"}; std::sort(vs.begin(), vs.end());
std::sort(vi.begin(), vi.end(), std::greater<int>());
for (int x : vi) std::cout << x << " "; std::cout << std::endl; for (const auto& s : vs) std::cout << s << " "; std::cout << std::endl;
return 0; }
|
常见陷阱
- 包含头文件时忘记
std:: 命名空间:STL的所有组件都在 std 命名空间中。
1 2 3 4 5
| vector<int> v;
std::vector<int> v;
|
- 用
sizeof 获取容器元素数量:sizeof 返回的是对象占用的字节数,不是元素个数。
1 2 3
| std::vector<int> v = {1, 2, 3}; std::cout << sizeof(v) << std::endl; std::cout << v.size() << std::endl;
|
- 迭代器与下标混用:
list 不支持随机访问,只能用迭代器。
1 2 3 4
| std::list<int> lst = {1, 2, 3};
auto it = lst.begin(); std::cout << *it << std::endl;
|
小结
STL是C++编程的基础设施,掌握它能让你的代码更简洁、更高效、更安全。记住三大组件的关系:容器存数据,迭代器遍历数据,算法操作数据。后续文章我们将逐一深入每个组件,从最常用的 string 开始。