什么是STL

STL(Standard Template Library,标准模板库)是C++标准库中最核心、最常用的部分。它提供了一套通用的、高效的、可复用的组件,让开发者不需要重复造轮子,就能完成绝大多数数据结构和算法相关的编程任务。

STL诞生于20世纪90年代初,由Alexander Stepanov和Meng Lee在HP实验室开发,后来被纳入C++标准。它的设计哲学是泛型编程(Generic Programming):将算法与数据类型解耦,用模板实现一套代码适配多种类型。

STL的三大组件

STL的核心由三大组件构成,它们紧密配合,形成了一个强大的工具体系。

1. 容器(Containers)

容器是用来存放数据的对象。你可以把它理解为”数据结构”的标准实现。STL的容器按逻辑结构可以分为三大类:

  • 序列容器:线性排列的数据,如 vectorlistdequearrayforward_list
  • 关联容器:基于键值对的有序数据结构,如 mapsetmultimapmultiset
  • 无序关联容器:基于哈希表的无序数据结构(C++11引入),如 unordered_mapunordered_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;

// C++11 范围for循环(底层就是迭代器)
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 << " ";
}
// 输出: 5 4 3 2 1
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> // 固定大小数组 (C++11)
#include <forward_list> // 单向链表 (C++11)
#include <map> // 有序映射
#include <set> // 有序集合
#include <unordered_map> // 无序映射 (C++11)
#include <unordered_set> // 无序集合 (C++11)
#include <stack> // 栈
#include <queue> // 队列和优先队列
#include <string> // 字符串

// 算法
#include <algorithm> // 排序、查找等70+算法
#include <numeric> // 数值算法(accumulate等)

// 迭代器工具
#include <iterator> // 迭代器适配器

// 其他工具
#include <functional> // 函数对象、bind
#include <memory> // 智能指针
#include <utility> // pair, move, swap

基本使用理念

泛型编程思想

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;
}

常见陷阱

  1. 包含头文件时忘记 std:: 命名空间:STL的所有组件都在 std 命名空间中。
1
2
3
4
5
// 错误
vector<int> v; // 编译错误

// 正确
std::vector<int> v;
  1. sizeof 获取容器元素数量sizeof 返回的是对象占用的字节数,不是元素个数。
1
2
3
std::vector<int> v = {1, 2, 3};
std::cout << sizeof(v) << std::endl; // 输出一个固定大小(通常是24),不是3!
std::cout << v.size() << std::endl; // 正确:输出3
  1. 迭代器与下标混用list 不支持随机访问,只能用迭代器。
1
2
3
4
std::list<int> lst = {1, 2, 3};
// lst[0]; // 编译错误!list没有operator[]
auto it = lst.begin();
std::cout << *it << std::endl; // 正确

小结

STL是C++编程的基础设施,掌握它能让你的代码更简洁、更高效、更安全。记住三大组件的关系:容器存数据,迭代器遍历数据,算法操作数据。后续文章我们将逐一深入每个组件,从最常用的 string 开始。