目录
一、什么是 STL?
二、STL 的版本
三、STL 的 6 大组件和 13 个头文件
四、学习 STL 的 3 个境界
五、STL 的缺陷
参考资料:
STL教程:C++ STL快速入门(非常详细) (biancheng.net)。
C++ STL是什么,有什么用? (biancheng.net)。
C++ STL版本有哪些? (biancheng.net)。
C++ STL基本组成(6大组件+13个头文件) (biancheng.net)。
一、什么是 STL?
STL 是 "Standard Template Library" 的缩写,中文可译为 "标准模板库" 或者 "泛型库",其包含有大量的类模板和函数模板,是 C++ 提供的一个基础模板的集合。
STL 最初由惠普实验室开发,于 1998 年被认定为国际标准,正式成为 C++标准库的重要组成部分。
值得一提的是,如今 STL 已完全被内置到支持 C++ 的编译器中,无需额外安装,这可能也是 STL 被广泛使用的原因之一。
STL 就位于各个 C++ 的头文件中,即它并非以二进制代码的形式提供,而是以源代码的形式提供。
从根本上来说,STL 是一些容器、算法和其他一些组件的集合,所有容器和算法都是总结了十几年来算法和数据结构的研究成果,汇集了许多计算机专家经验的基础上实现的,因此可以说,STL 基本上达到了各种存储方法和相关算法的高度优化。
注意,这里提到的容器,本质上就是封装有数据结构的类模板,例如 list、vector、set、map 等。
二、STL 的版本
自 1998 年 ANSI/ISO C++ 标准正式定案,C++ STL 规范版本正式通过以后,由于其是开源的,各个 C++ 编译器厂商在此标准的基础上,实现了满足自己需求的 C++ STL 泛型库,主要包括:
-
HP STL
HP STL 是 Alexandar Stepanov(STL 标准模板库之父)在惠普 Palo Alto 实验室工作时,与 Meng Lee 合作完成的。HP STL 是开放源码的,即任何人都可以免费使用、复制、修改、发布和销售该软件以及相关文档,但前提是必须在相关文档中,加入 HP STL 版本信息和授权信息。
HP STL 是 C++ STL 的第一个实现版本,其他版本的 C++ STL 一般是以 HP STL 为蓝本实现出来的。不过,现在已经很少直接使用此版本的 STL 了。
-
SGI STL
Stepanov 在离开 HP 之后,就加入到了 SGI 公司,并和 Matt Austern 等人共同开放了 SGI STL。严格意义上来说,它是 HP STL 的一个继承版本。和 HP STL 一样,SGI STL 也是开源的,其源代码的可读性非常好,并且任何人都可以修改和销售它。
注意,SGI STL 只能算是一个 "民间" 版本,因此并不是所有支持 C++ 的编译器都支持 SGI STL,唯一能确定的是,GCC(Linux 下的 C++ 编译器)是支持的,所以 SGI STL 在 Linux 平台上的性能非常出色。
-
STLport
为了使 SGI STL 的基本代码适用于 VC++ 和 C++ Builder 等多种编译器,俄国人 Boris Fomitchev 建立了一个 free 项目来开发 STLport,此版本 STL 是开放源代码的。
-
PJ STL
PJ STL(全称 P.J Plauger STL)是由 P.J.Plauger(美国人,1965 年毕业于普林斯顿大学,物理学专业学士)参照 HP STL 实现出来的,也是 HP STL 的一个继承版本,因此该头文件不仅包含 HP STL 的相关授权信息,同时还有 P.J.Plauger 本人的授权信息。
其实 PJ STL 是 P.J.Plauger 公司的产品,尽管该公司当时只有 3 个人。
PJ STL 被 Visual C++ 编译器所采用,但和 PH STL、SGI STL 不同的是,PJ STL 并不是开源的。
-
Rouge Wave STL
该版本的 STL 是由 Rouge Wave 公司开放的,也是继承 HP STL 的一个版本,它也不是开源的。
Rouge Wave STL 用于 Borland C++ Builder 编译器中,我们可以在 C++ Builder 的 Include 子目录中找到该 STL 的所有头文件。
值得一提的是,尽管 Rouge Wave STL 的性能不是很好,但 C++ Builder 对 C++ 语言标准的支持还算不错,所以一定程度上使 Rouge Wave STL 的表现得以改善。
遗憾的是,由于 Rouge Wave STL 长期没有更新且不完全符合标准,因此 Rouge Wave STL 在 6.0 版本时改用 STLport 版本(之后的版本也都采用了 STLport),不过考虑到和之前版本的兼容,6.0 版本中依旧保留了 Rouge Wave STL。
Rouge Wave 公司在 C++ 程序库领域应该说是大名鼎鼎,对 C++ 标准化的过程出力甚多。不过 Rouge Wave STL 版本不仅更新频率慢,费用还高,基于这两个原因,Borland 在 6.0 版本决定奇用 Rouge Wave STL 而改用 STLport。
三、STL 的 6 大组件和 13 个头文件
通常认为,STL 是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 个部分构成,其中后面 4 个部分是为前面 2 个部分服务的,它们各自的含义如下表所示:
STL 的组成部分 | 含义 |
---|---|
容器(Containers) | 一些封装数据结构的类模板,例如 vector 向量容器、list 列表容器等 |
算法(Algorithms) | STL 提供了非常多(大约 100 个)的数据结构算法,它们都被设计成一个个的函数模板,这些算法在 std 命名空间中定义,其中大部分算法都包含在头文件 <algorithm> 中,少部分位于头文件 <numeric> 中 |
迭代器(Iterators) | 在 C++ STL 中,对容器中数据的读和写,是通过迭代器完成的,扮演着容器和算法之间的胶合剂 |
函数对象(Functors) | 如果一个类将 () 运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象(又称仿函数) |
适配器(Adapters) | 可以使一个类的接口(模板的参数)适配成用户指定的形式,从而让原本不能在一起工作的两个类工作在一起。值得一提的是,容器、迭代器和函数都有适配器。 |
内存分配器(Allocators) | 为容器类模板提供自定义的内存申请和释放功能,由于往往只有高级用户才有改变内存分配策略的需求,因此内存分配器对于一般用户来说,并不常用。 |
另外,在惠普实验室最初发行的版本中,STL 被组织成 48 个头文件;但在 C++ 标准中,它们被重新组织为 13 个头文件:
<iteraotr> <functional> <vector> <deque>
<list> <queue> <stack> <set>
<map> <algorithm> <numeric> <memory>
<utility>
按照 C++ 标准库的规定,所有标准头文件都不再有扩展名。以 <vector> 为例,此为无扩展名的形式,而 <vector.h> 为有扩展名的形式。
但是,或许为了向下兼容,或许是为了内部组织规划,某些 STL 版本同时存储具备扩展名和无扩展名的两份文件(例如 Visual C++ 支持的 Dinkumware 版本同时具备 <vector> 和 <vector.h>);甚至有些 STL 版本同时具有 3 种形式的头文件(例如 SGI 版本同时拥有 <vector>、<vector.h> 和 <stl_vector.h>);但也有个别的 STL 版本只存在包含扩展名的头文件(例如 C++ Builder 的 Rauge Ware 版本只有 <vector.h>)。
建议读者养成良好的习惯,遵照 C++ 规范,使用无扩展名的头文件。
四、学习 STL 的 3 个境界
简单总结一下,学习 STL 的 3 个境界分别为:能用、明理、能扩展。
五、STL 的缺陷
-
STL 库的更新太慢了。上一版靠谱的是 C++98,中间的 C++03 基本是一些修订,C++11 出来已经相隔 13 年了,STL 才进一步更新。
-
STL 现在都没有支持线程安全。并发环境下需要我们自己加锁,且锁的粒度是比较大的。
-
STL 极度地追求效率,导致内部比较复杂,比如类型萃取、迭代器萃取。
-
STL 的使用会有代码膨胀的问题,当然这是模板语法本身导致的。