前言
STL的algorithm包含了各种算法的实现,这些算法必须能对不同的容器和容器的适配器进行操作,比如下面的例子:
#include <bits/stdc++.h>
using namespace std;
int main(){
vector<int> m_vec{1, 3, 2, 4};
deque<int> m_deque{1, 3, 2, 4};
sort(m_vec.begin(), m_vec.end());
sort(m_deque.begin(), m_deque.end());
return 0;
}
对于上面代码中的两个sort,如果通过函数重载来实现对不同容器类型的排序,用户自定义需要考虑的问题增加了很多,不利于STL的扩展。为此,STL提供了Iterator作为将算法和容器连接起来的桥梁,下面我们来看看iterator相关的源码,同样的,代码会在最后给出。
Iterator类型
STL提供类5中类型的Iterator
- input_iterator :用于读取所指向元素的输入
- output_iterator:用于向所指向元素写入
- forward_iterator:可前向移动的可读取指向元素的迭代器
- bidirectional_iterator:可双向移动的可读取指向元素的迭代器
- random_access_iterator:可双向移动的,能在常数时间内移动到任意元素的可读迭代器
他们之间具有如下继承关系:
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
对于用户自定义的iterator,最好需要继承std::iterator,其中包含了STL需要的五种类型,保证容器在自定义类型中的使用。
// 用户自己的写的迭代器最好继承此 std::iterator
#ifdef __STL_USE_NAMESPACES
template <class _Category, class _Tp, class _Distance = ptrdiff_t,
class _Pointer = _Tp*, class _Reference = _Tp&>
struct iterator {
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
#endif /* __STL_USE_NAMESPACES */
iterator可以看作进化的指针,以vector为例,我们来看看与iterator相关的代码:
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class vector : protected _Vector_base<_Tp, _Alloc>
{
public:
typedef _Tp value_type;
typedef value_type* iterator; // vector 的迭代器
typedef const value_type* const_iterator;
}
可以发现,假如我们声明vector<int>
,_Tp就为int,iterator的类型为int*,即一个普通指针。STL还实现了一个基于vector的位图,称为bvector,bvector的迭代器就相对复杂的多,在下面的代码中可以看到bvector迭代器的继承路径。与vector的迭代器不同,_Bit_iterator不是通过指针类型被使用,但为了模仿指针的行为,_Bit_iterator重载了operator*/operator&/operator->,以匹配指针的行为。
struct _Bit_iterator_base : public random_access_iterator<bool, ptrdiff_t>
struct _Bit_iterator : public _Bit_iterator_base
不同的容器通过继承不同的iterator类型,可能具有不同特性的iterator,每种容器的iterator将在介绍容器时介绍,但不管是哪种iterator,都必须具有下面5种元素类型。
- iterator_category:迭代器类别;
- value_type:迭代器解引用后的值的类型;
- difference_type:两个迭代器之间的距离;
- pointer:被迭代类型的指针;
- reference:被迭代类型的引用;
auto_ptr
在SGI的memory.h文件中,介绍了auto_ptr,但auto_ptr已被废弃,取而代之的是另外三种智能指针,可在c++11智能指针中查看相关特性。
iterator使用
最后给出一个通过iterator遍历vector的简单使用代码:
#include <bits/stdc++.h>
int main(){
std::vector<int> nums = {1, 2, 3, 4};
std::vector<int>::iterator it = nums.begin(); //c++11以后,可以直接写成auto it = nums.begin();
for(;it != nums.end();++it){
std::cout << *it << std::endl;
}
return 0;
}
nums.begin()
将返回指向nums第一个元素的迭代器,而nums.end()并不指向任何元素,这是一个在容器元素末尾的哨兵,当访问到nums.end()时,说明已经完成遍历。
SGI STL源码
iterator相关源码:iterator