STL简述
STL(Standard Template Library)是C++泛型编程(template技术)的集大成者, 迭代器在STL中发挥重要的作用. 在STL中有3个重要的概念:
- 容器:包括顺序容器(vector, list)和关联容器(map, set)
- 算法:各种操作容器的函数模版(count, count_if)
- 迭代器:作为算法和容器的桥梁, 让算法独立于容器发展
迭代器的重要作用就是让容器和算法解耦合, 或者说让数据和操作解耦合, 算法利用迭代器作为输入, 从而摆脱对容器具体数据的访问. 容器生成的迭代器用于遍历容器中的每个元素, 同时避免暴露容器的内部数据结构和实现细节.
这里通过一个算法的例子来展示迭代器的使用:
template <class Iterator, class T>
Iterator find(Iterator begin, Iterator end, const T& value)
{
while (begin != end && *begin != value)
++begin;
return begin;
}
注意这个例子展示的算法find()可以用于各种各样的容器(vector, map…), 试想没有迭代器, 那就需要为每个容器都实现一个find()算法, 何其繁琐.
简单的迭代器
在迭代器的实现中, 经常需要访问迭代器所指对象的类型,称之为该迭代器的value type. 利用内嵌类型申明typedef可以轻松实现隐藏所指对象类型, 如下迭代器的实现:
templates <class T>
struct Iterator {
typedef T value_type;
//...
};
泛型算法就可以通过typename Iterator::value_type来获得value type.
template <class Iterator>
typename Iterator::value_type getValue(Iterator iter) {
return *iter;
}
萃取的概念
在简单的迭代器中, 通过内嵌类型申明很好的隐藏了所指对象的内部细节, 实现了数据和算法的分离, 但是STL要求支持迭代器的算法, 应该也要支持原生指针, 比如
Int array[4] = {1, 2, 3, 4};
find(array, array+4, 3);
这里存在的一个难题就是原生指针不能内嵌类型申明, 于是这里就需要多一层的封装,萃取编译技术应运而生.
萃取(traits)编程技术,归纳成四个字就是:特性萃取。在迭代器的上下文中, 就是萃取出迭代器的value type, 可以概念上认为迭代器所指对象的类型(value type)就是该迭代器的一个特性(traits)
template <class Iterator>
struct iterator_traits {
typedef typename Iterator::value_type value_type;
//...
};
有了iterator_traits,就可以改写算法getValue():
template <class Iterator>
typename iterator_traits<Iterator>::value_type
getValue(Iterator iter) {
return *iter;
}
多一层封装的好处在于, iterator_traits是一个C++类模版,可以为原生指针(特殊的迭代器)定义模版偏特化, <<泛型思维>>对模版偏特化做出的定义是: 针对(任何)template参数进一步的条件限制所设计出来的一个特化版本, 而原生指针T*, const T*就是一种偏特化.
template <class T>
struct iterator_traits<T*> {
typedef T value_type;
};
template <class T>
struct iterator_traits<const T*> {
typedef T value_type;