我们曾学习了各种各样的数据结构,包括顺序表,链表,树,堆,栈,队列等等,假如我们要去使用它们,假如每次都要我们自己去实现一份出来似乎太过于麻烦,那么有没有什么方法可以很方便的使用它们呢?这就需要我们来了解一下STL了。
1.什么是STL
或许有人曾听说过:“没有学过STL你怎么敢说自己会C++”,那么STL到底是什么呢?STL即 Standard Template Library,也就是标准模板库,它是C++标准库中的重要组成部分,它提供了一系列通用的、可复用的算法和数据结构。它主要有六大组件:
a.容器(STL的“仓库”,装数据的不同抽屉)
定义:存储数据的数据结构,封装了内存管理
分类:
1.序列式容器(按顺序存储):vector
(动态数组)、list
(双向链表)、deque
(双端队列)
2.关联式容器(键值对/有序):map
(有序键值对)、set
(有序去重)、unordered_map
(哈希表)
…
示例:
vector<int> nums = {1,2,3}; // 最常用的动态数组容器
map<string, int> scores; // 按key排序的字典
b.迭代器
定义:容器的”指针“,统一访问容器元素的接口。
分类:
1.正向迭代器(++单向移动)
2.随机访问迭代器(支持+/-等)
示例:
#include<vector>
int main()
{vector<int> nums = { 1,2,3 };for (auto it = nums.begin(); it != nums.end(); ++it){cout << *it; // 用迭代器遍历容器}return 0;
}
c.算法(STL 的 “工具库”)
定义: 操作容器元素的“通用函数”
分类:
1.非质变算法(不改变元素):find
(查找)、for_each
(遍历)
2.质变算法(改变元素):sort
(排序)、reverse
(反转)
示例:
#include<vector>
#include<algorithm> //使用库中算法需要包含该头文件
int main()
{vector<int> nums = { 3,2,1 };sort(nums.begin(), nums.end());//sort排序for (auto it = nums.begin(); it != nums.end(); ++it){cout << *it; }return 0;
}
d.仿函数(“带记忆的函数”,给算法定制行为)
定义:重载operator()
的类,比普通函数更灵活(可带状态)。
分类:
1.预定义仿函数:std::less<int>
(小于)、std::plus<int>
(加法)
2.自定义仿函数:
struct MyCmp {bool operator()(int a, int b) { return a % 2 < b % 2; } // 按奇偶排序
};
sort(nums.begin(), nums.end(), MyCmp()); // 传入仿函数
//这里仅做示例,后续有机会再做具体讲解
e.适配器(“接口转换器”,让旧组件焕发新生)
定义:修改现有的组件接口,使其适配新场景
分类:
1.容器适配器:如stack
(默认基于deque
)、queue
(默认基于deque
),它们的底层都可以通过已有的deque稍作修改得到。
2.迭代器适配器:如reverse_iterator
(反向迭代)、insert_iterator
(插入迭代)(这里暂不做详细介绍)
f.空间配置器(STL的“内存管家”)
定义:封装内存分配细节
作用:
1.控制容器的内存申请/释放(如vector动态扩容时的内存管理)
2.支持自定义内存池
class MyAllocator { /* 自定义内存分配逻辑 */ };
vector<int, MyAllocator> nums; // 替换默认分配器
2.STL的版本
HP版本(原始版本)
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,唯一的条件就是也需要向原始版本一样做开源使用。 后续很多版本都在此基础上发展而来。
P. J. 版本
由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改。
RW版本
由Rouge Wage公司开发,继承自HP版本,被C++ Builder 采用,不能公开或修改,可读性一般。
SGI版本
由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。我们后续学习STL主要参考的就是这个版本。
3.STL优缺点
1.优点
- 泛型编程,高度复用
容器 / 算法 / 迭代器分离:一套算法(如sort
)适配所有容器(如vector
/list
),通过迭代器解耦数据与操作,减少重复代码。
例:for_each(vec.begin(), vec.end(), print)
同时支持数组、链表等。
- 性能优化(以 SGI 版本为例)
空间配置器:内存池机制减少碎片化(如vector
批量申请内存),比原生new
更高效。
例:vector
扩容时默认按 1.5 倍增长,减少频繁内存分配。
- 跨平台一致性
主流编译器(GCC、Clang、MSVC)均实现 STL,代码可移植性强(需注意版本差异,如 MSVC 的 P.J. 版命名怪异)。
- 工业级成熟度
经过 30 年迭代,覆盖 90% 日常需求(容器、算法、仿函数),避免 “重复造轮子”。
2.缺点
- STL库的更新较慢,上一版靠谱是C++98,中间的C++03基本一些修订。C++11出来已经相隔了13年,STL才进一步更新。
- STL现在都没有支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。
- STL极度的追求效率,导致内部比较复杂。对初学者来说需要花费一定时间才能够理解,比如类型萃取,迭代器萃取等。
- 由于模板语法,STL的使用会有代码膨胀的问题,比如使用vector /vector/vector这样会生成多份代码。