设计模式--迭代器iterator
我们知道STL两个主要内容就是容器(containers)和算法(algoritms),两者是分开设计的。关于各自独立的实现,c++中的class template和function template能很好的完成这个目标。而将两者胶合起来,则需要iterator的帮助。这就使得iterator成了STL设计中重要的一环。
迭代器是一种抽象的设计概念,《设计模式》中提供的23种设计模式中的一种。以下是对于其适用性的描述:
1.访问一个聚合对象的内容而无需暴露它的内部表示
2.支持对聚合对象的多种遍历
3.为遍历不同的聚合结构提供一个统一接口
根据《设计模式》中的观点,创建迭代器的参与者可以包含以下几个:
-
Iterator(迭代器)
迭代器定义和访问的接口
-
ConcreteIterator(具体迭代器)
具体实现迭代器接口,不同的类有不同的迭代实现 跟踪遍历位置
-
Aggregate(聚类)
定义和创建相应迭代器对象的接口
-
ConcreteAggregate(具体聚类)
具体聚合实现创建相应迭代器的接口
所以创建iterator又是一种Factor Method模式,这样做就实现了聚类与迭代机制的分离。当然,STL中的iterator并不完全按这个分层的机制实现。但是,总体上按这个模式来的,对所有的iterator有一个统一的抽象,其中定义了基本的内部类型,和基本的通用的函数操作,而对不同的容器,实现专属迭代器。
迭代器的分类
迭代器作为访问容器的一个工具,根据访问权限和移动特性可已将其分为以下几类:
-
Input iterator
单向(operator ++),只读对象,不允许外界改变
-
Output iterator
单向(operator ++),只写
-
Forward iterator
单向(operator ++),能写能读
-
Bidirectional iterator
双向(operator ++/--),能写能读
-
Random Access iterator
双向(operator ++/--),能写能读,支持随机访问(operator +/- n)
之所以要区别这几种迭代器因为不同的迭代器,某些操作的执行效率会不一样。
迭代器的基本操作
STL还在bits\stl_iterator_base_funcs.h中定义了iterator的一些基本操作,主要包括以下几个:
distance
-
函数声明:
difference_type distance(InputIterator first,InputIterator last);
-
作用: 求两个迭代器的距离
advance
-
函数声明:
void advance(InputIterator& i, Distance n);
-
作用: 将迭代器i移动n个位置,n可以是负数(双向迭代器)
以下是c++11后增加的两个函数(参考MinGW g++4.8.1)
next
-
函数声明:
ForwardIterator next(ForwardIterator __x, difference_type __n = 1);
-
作用:将迭代器x后移一位,并返回x。
prev
-
函数声明:
BidirectionalIterator prev(_BidirectionalIterator __x,difference_type __n = 1);
-
作用:将双向迭代器x前移一位,并返回x。
上面的几个声明是简化的形式,具体实现时还需要修改。
框架的选择
应该包括哪些操作?应该把哪些操作交给容器?抽象到什么程度?考虑清楚这些问题,直接关系到后面的容器该的怎么设计。在比较了SGI STL和GNU gcc的迭代器设计之后,我决定采用gcc STL的的设计。gcc STL的设计中,container都有自己的iterator,所以一般以[container]::[iterator]的形式访问容器的iterator。这并不是说iterator都直接设计在container里面,虽然不同的容器需要不同的迭代器,但是我们可以对迭代器某些通用的属性和操作进行抽象。所以,迭代器是无法完全从容器中抽离出来单独设计,迭代器的设计主要包括通用抽象部分和具体容器部分。下面以gcc STL的vector的迭代器为例分析迭代器的实现:
TL的vector的迭代器为例分析迭代器的实现:-
通用的部分:
在bits\stl_iterator_base_type.h和bits\stl_iterator_base_funcs.h中,包含了 所有迭代器相关的类型(如iterator,iterator_traits),函数(如advance,distance)
-
适配器:
在bits\stl_iterator.h中基于前面的iterater,实现了一些iterator适配器,比如 __normal_iterator,reverse_iterator等。
-
容器部分:
在bits\stl_vector.h中,使用__normal_iterator<pointer,Container>建立了一个 vector专属的迭代器。
大致上,迭代器的设计包括以上的部分。但是也有特例,比如std::list的迭代器是在内部完全重新写过的。
经过各方面的考量和取舍,我将通用部分合在iterator_base.h
中,将适配器写在stl_iterator.h
中,主要实现_normal_iterator
,其他的放到adapter部分。而容器部分就放到以后实现容器的时候再说。
完整代码
//my_iterator_base.h
#ifndef MY_ITERATOR_H_INCLUDED
#define MY_ITERATOR_H_INCLUDED
#include<iostream>
#include<typeinfo> //for typeid
using std::cout;
using std::endl;
namespace juine
{
//5个迭代器类型
struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag:public input_iterator_tag,public output_iterator_tag{};
struct bidirectional_iterator_tag:public forward_iterator_tag{};
struct random_access_iterator_tag:public bidirectional_iterator_tag{};
template<class T>
class Iterator_base
{
public:
//作为迭代器所必需的元素(萃取5元素)
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef size_t difference_type;
//iterator_category 需要根据迭代器的类别来判断
//构造函数和析构函数
Iterator_base(T* p=0):point(p){}
//copy构造函数怎么写:
Iterator_base(const Iterator_base& t):point(t.point){}
~Iterator_base(){delete point;}
//实现*和->的引用,++
value_type& operator*(){ return *point; }
pointer operator->(){ return point; }
Iterator_base operator++()
{
point++;
return *this;
}
Iterator_base operator++(int)
{
Iterator_base tmp(*this);
++*this;
return tmp;
}
bool operator!=(Iterator_base iter)
{
if(point==iter.point)
return true;
return false;
}
private:
T* point;
};
//萃取出迭代器中的各个性质
template<class T>
struct strait
{
//不能写成其他的 ,因为要和标准的STL实现无缝链接
typedef typename T::value_type value_type;
typedef typename T::reference reference;
typedef typename T::difference_type difference_type;
typedef typename T::pointer pointer;
typedef typename T::iterator_category iterator_category;
};
//偏特化
template<class T>
struct strait<T*>
{
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef size_t difference_type;
typedef random_access_iterator_tag iterator_category;
};
template<class T>
struct strait<const T*>
{
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef size_t difference_type;
typedef random_access_iterator_tag iterator_category;
};
//迭代器常见操作方法之advance方法
template<class InputIterator>
void __advance(InputIterator& iter,size_t n,input_iterator_tag )
{
while(n--)
iter++;
cout<<"调用的是InputIterator迭代器"<<endl;
}
template<class InputIterator>
void __advance(InputIterator& iter,size_t n,forward_iterator_tag )
{
__advance(iter,n,InputIterator());
cout<<"调用的是ForwardIterator迭代器";
}
template<class InputIterator>
void __advance(InputIterator& iter,size_t n,bidirectional_iterator_tag )
{
if(n>0)
while(n-->0)
iter++;
else
while(n++>=0)
iter--;
cout<<"调用的是BidirectionalIterator迭代器"<<endl;
}
template<class InputIterator>
void __advance(InputIterator& iter,size_t n,random_access_iterator_tag )
{
iter+=n;
cout<<"调用的是RandomIterator迭代器"<<endl;
}
//对外统一的接口
template<class InputIterator>
void my_advance(InputIterator& iter,size_t n)
{
cout<<"自制advance"<<endl;
typedef typename strait<InputIterator>::iterator_category iterator_category;
__advance(iter,n,iterator_category());
}
//迭代器常见操作方法之distance方法
template<class InputIterator>
typename strait<InputIterator>::difference_type
__distance(InputIterator iter1,InputIterator iter2,input_iterator_tag)
{
typedef typename strait<InputIterator>::difference_type difference_type;
difference_type length=0;
while(iter1!=iter2)
{
iter1++;
length++;
}
return length;
}
template<class InputIterator>
typename strait<InputIterator>::difference_type
__distance(InputIterator iter1,InputIterator iter2,forward_iterator_tag)
{
return __distance(iter1,iter2,input_iterator_tag());
}
template<class InputIterator>
typename strait<InputIterator>::difference_type
__distance(InputIterator iter1,InputIterator iter2,random_access_iterator_tag)
{
typedef typename strait<InputIterator>::difference_type difference_type;
difference_type length=iter2-iter1;
return length;
}
//对外实现统一的接口
template<class InputIterator>
typename strait<InputIterator>::difference_type my_distance(InputIterator iter1,InputIterator &iter2)
{
typedef typename strait<InputIterator>::iterator_category iterator_category;
typedef typename strait<InputIterator>::difference_type difference_type;
difference_type length=__distance(iter1,iter2,iterator_category());
return length;
}
}
#endif // MY_ITERATOR_H_INCLUDED
测试代码
//test_iterator.cpp
#include<vector>
#include<iostream>
#include"my_iterator_base.h"
using namespace juine;
using namespace std;
int main()
{
int a[5]={1,2,3,4,5};
vector<int> vec(a,a+5);
vector<int>::iterator iter=vec.begin();
my_advance(iter,2);
cout<<"my_advence调用后:"<<*iter<<endl;
vector<int>::iterator iter2=vec.begin()+4;
cout<<"distance距离为:"<<my_distance(iter,iter2);
return 0;
}
测试结果截图:
从结果可以看出,该迭代器实现了对STL的无缝链接,基本上达到我们预期的结果!