回聊聊STL标准库(一)- 迭代器 inerators(1)

来聊聊STL标准库(一)--- 迭代器 inerators(1)

迭代器 --- inerators


迭代器是设计模式中的一种,具体的描述是,有这么一种方法,可以依次的访问某一个集合中的每一个元素,而且又不需要暴露集合内部元素的细节,那这种表达方式就是迭代。

迭代的思想后来被很多编程语言收录了,比如python的 for ... in ...语句实际上就是一个迭代器。当然,在c++11最新的标准中,也提供了对迭代的原生支持。

在我们编写STL程序时,迭代器是使用频率非常高的,比如下面这种用法你一定用过:

int a[5]={1,2,3,4,5};
vector<int> list(a,a+5);

vector<int>::iterator it;
for (it=vector.begin();it!==vector.end();it++)
{
    cout << *it << endl;
}

这是就是一个标准的迭代器的用法,我们这里集合内部是int型的,你完全可以修改成任何类型,程序不需要做任何改变就能运行,这就是迭代器,他屏蔽了集合内部的元素细节,并且提供对集合内部元素的依次访问。

在迭代器的设计中,我们首先要解决两个问题

  • 迭代参数的类型
  • 迭代的返回类型

迭代参数的类型


在迭代器的实现中,还有一个是迭代器的类型,比如上面这个例子,迭代器的类型是int,当然,你也可以换成其他你想要的类型,但是迭代器内部是怎么知道这个类型的呢?你并没有将int这个类型传进去,STL是怎么来知道你的类型的呢?这里使用了函数模板的参数推导机制,如果我们把这个机制摘出来,简单的来说是这样的。

首先,函数原型是void func(type it),我们把她写成:

template<class I>
void func(I it)
{
    //do some thing
    __func(it,*it);
}

然后,再来一个实际处理函数

template<class I,class T>
void __func(I it,T t)
{
    T tmp;
    //实际操作在这完成

}

主函数是:

int main()
{
    int i;
    func(&i);
}

我们来看看这个流程,当main调用func时,I是int*类型,当func调用__func时,变成了__func(int* it,int t),此时,在__func内部,就得到了i的类型int,看上去好像比较麻烦,你仔细学习一下c++的函数模板就能理解这个做法了,这样,开放给外面用的func函数实际上不用知道传入的类型,在__func中会自动推导出这个类型来,然后再做相应的事情,迭代器也是使用类似的技术,让集合的内部对于外界来说变成隐藏的了。

迭代的返回类型


但是其实有这个是远远不够的,因为在迭代器的实现中,很多时候并不是传个参数就行了,有时候还需要这个函数可以返回,并且这个返回值一般也是类型不固定的,这就需要内置类型声明,什么是内置类型声明呢?像这样:

temlate<class T>
struct MyIt{
    typedef T new_type;
};
//然后函数声明这样弄
template<class I>
typename I::new_type func(I it){ ... }

认真看一下,OK,返回值类型变换也搞定了。

好了,这两个问题至少在技术上是可以解决的了,实际的设计中关于这两个还有个原生指针的问题,因为原生指针的返回类型没办法用内置类型声明来解决,具体解决方法大家有兴趣可以自己查查。