C++ STL六大组件
STL提供了六大组件,彼此组合套用协同工作。这六大组件分别是:
-
容器:各种数据结构,如 vector,list,deque,set,mep等。
-
算法:各种常用的算法,提供了执行各种操作的方式,包括对容器内容执行初始化,排序,搜索和转换等操作,比如sort,search,copy,erase。
-
迭代器:迭代器用于遍历对象集合的元素,扮演容器与算法之间的胶合剂,是所谓的"泛型指针",一共有五种类型,以及其他衍生变换。
例如:operator*,operator->,operator++,operator–等指针操作予以重载的class template。
所有的STL容器附带有自己的专属迭代器,因为只有容器设计者才知道如何遍历自己的元素。
-
仿函数:也成函数对象,行为类似函数,可作为算法的某种策略。从实现角度来看,仿函数是一种重载了operator()的class或者class template。
-
适配器:一种修饰容器或者仿函数或迭代器接口的东西。例如:STL提供的queue和stack,就是一种空间适配器,因为他们底部完全借助于deque。
-
分配器:也成为空间配置器,负责空间的配置与管理。
STL六大组件的交互关系
容器
一个容器就是一些特定类型对象的集合。STL中容器分为两大类:序列式容器和关联式容器。
序列式容器为程序员提供了控制元素存储和访问顺序的能力。这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应。
除了序列式容器之外,标准库还定义了三个序列式容器适配器:
stack,queue和priority_queue。适配器时标准库中的一个通用概念,容器,迭代器和仿函数都有适配器。本质上,一个适配器是一种机制,是某种事务的行为看起来像另一种事物一样。
和序列式容器对应的是关联式容器,关联式容器中的元素是按关键字来保存的。关联式容器支持高效的关键字查询和访问,STL有两个主要的关联容器:map和set。
迭代器
迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。迭代器本质就是一种指针。事实上,C++的指针也是一种迭代器。但是迭代器不仅仅是指针,因此不能认为他们一定具有地址值。例如:一个数组索引,也可以认为是一种迭代器。
迭代器有各种不同的创建方法。程序可能把迭代器作为一个变量创建,一个STL容器类可能为了使用一个特定类型的数据而创建一个迭代器。作为指针,必须能够使用*操作符来获取数据,还可以使用其他数学操作符例如++操作符来递增迭代器,以访问容器中的下一个对象。如果迭代器到达了容器中的最后一个元素的后面,则迭代器变成past-the-end值。使用一个past-the-end值得到的指针来访问对象是非法的,就好像使用NULL或者初始化的指针一样。
对于STL数据结构和算法,可以使用五种迭代器。
迭代器类型 | 说明 |
---|---|
input iterator | 数据只读 |
output iterator | 数据只写 |
foreard iterator | 读写操作,并能向前推进迭代器 |
bidirectional iterator | 读写操作,并能向前和向后操作 |
random access iterator | 读写操作,并能在数据中随机移动 |
算法
STL通过函数模板提供了很多作用于容器的通用算法,例如查找,插入,删除,排序等。这些算法均需要引入头文件。
所有的STL算法都作用在由迭代器[first,last)所标示出来的区间上,可以分为两大类:
- 质变算法:运算过程中会更改区间迭代器所指的元素内容,如分割,删除等算法
- 非之变算法:运算过程中不会更改区间迭代器所指的元素内容,如匹配,计数等算法。
所有泛型算法的前两个参数都是一对迭代器,通常为first和last,用以标示算法的操作区间。
总结
STL提供了六大组件,而从代码广义上来讲,主要分为三类:容器,迭代器和算法。几乎所有的代码都采用模板类和模板函数的方式,这相较于传统的由函数和类组成的库来说提供了更好的代码复用机会。
算法,容器,迭代器三者的关系是:算法操作数据,容器存储数据,迭代器作为算法操作容器的桥梁,迭代器与容器一一对应。
STL的中心思想在于将数据容器和算法分开,彼此独立设计,最后以一帖胶着剂将他们撮合在一起。
STL的一个重要特点是数据结构和算法的分离,正是这种分离设计,使得STL变得非常通用。例如STL的sort()函数是完全通用的,可以用来操作几乎任何数据集合。
数据结构和算法的分离,正是这种分离设计,使得STL变得非常通用。例如STL的sort()函数是完全通用的,可以用来操作几乎任何数据集合。
STL另一个重要特性是它不是面向对象的。为了具有足够的通用性,STL主要依赖于模板,而不是OOP的三个要素,这使得在STL中找不到任何明显继承关系。