##一、什么是迭代器?##
迭代器(iterator)其实和STL息息相关,STL里所有的容器都有迭代器的概念。迭代器有只读或可写之分,也有随机或顺序之分。其实可以把迭代器理解成特别的指针,它具有指针基本的操作(解引用*
,自加++,自减--
,指向结构体成员->
等操作)。迭代器的特别之处在于写基于迭代器的算法时不需要知道容器的类型,迭代器对不同的容器提供了效果一致的使用方法,<algorithm>中的诸多函数也正是基于迭代器来实现的。
##二、怎么获取迭代器?##
通常从容器中获取迭代器可以使用std::begin()
和std::end()
两个函数,分别获得容器的begin
和end
。
用法如下:对于容器container
,std::begin(container)
和std::end(container)
即能获得一对迭代器。
除了这两个函数以外,还有std::cbegin()
(c for constant),std::rbegin()
(r for reverse),std::crbegin()
以及它们对应的end
函数,依次来获得const的,倒序的,const且倒序的迭代器。
而为了使所有的容器支持迭代器,正如一
中所述需要满足一些算法的泛用性,上述函数对于数组也可以取得对应的一对迭代器。
当然除了使用上述函数以外,STL内的容器也都有一些成员函数来获取对应的迭代器。
如begin()
,end()
,rbegin()
,rend()
,cbegin()
,cend()
,crbegin()
,crend()
。
比如对于vector容器v,可以使用v.begin()
和v.end()
来获取一对迭代器。
##三、为什么要以“对”来谈论迭代器?##
在这里可能会产生疑问,为什么要以“对”来谈论迭代器呢?
答案是:一对迭代器表示了一个范围,单个迭代器没有什么意义。
这里谈到了迭代器表示的范围,这个范围呢,是一个左闭右开的区间,begin
处闭,end
处开,也就是说对于我们获取到的一对begin
和end
迭代器,它表示着[begin, end)
这个范围,那么对于某个迭代器iter
可以用begin <= iter && iter < end
来判断其是否属于这个区间,注意不是所有迭代器都能比较大小。
所以,end
取得的迭代器表示着数据的结尾,像是一堵墙,墙不能存储数据,可以说这个结尾是不存在的,因而不能对end
解引用获得数据,那样做是会失败的。
如果迭代器iter
边访问数据边自加最终与end
的值相等,也就意味着到达了数据的末尾。
##四、迭代器怎么使用?##
现在我们有一个vector<int>
容器v
,其中数据为[5, 4, 3, 2, 1, 0]
。
怎么用迭代器去访问数据呢?
来看一段代码片段:
for(auto iter = v.begin(); i != v.end(); i++) {
cout << *iter << endl;
}
这里的auto
关键字是C++11的新特性,这将会允许编译器自动推导变量类型(当然不是C中那完全没有存在感的auto
关键字),不然的话我们就得写vector<int>::iterator iter
,适当地使用auto可以极大地增加代码的整洁程度,当然前提是适当的使用,如果使用不当会获得错误的类型或者影响了代码的可读性。
那么现在来想想看它的输出是什么呢?
没错,正是5、4、3、2、1、0。
那现在来看另一段代码:
for(auto iter = v.rbegin(); i != v.rend(); i++) {
cout << *iter << endl;
}
这样的话,输出就变成了0、1、2、3、4、5。因为现在使用的是倒序的迭代器,千万不要以为倒序迭代器就应该用--
,那样的话倒序迭代器存在的意义是什么?访问迭代器的方法很统一,也正是如此基于迭代器的算法才有高度的泛用性。
<algorithm>
中的sort()
函数正是基于迭代器来实现的,默认排序是从小到大。
如果我们对上面的v
容器使用sort()
函数,如下:
sort(v.begin(), v.end());
那么v
的数据就会变成[0, 1, 2, 3, 4, 5]
。
而如果这么用:
sort(v.rbegin(), v.rend());
那么v
的数据就仍然是[5, 4, 3, 2, 1, 0]
,因为虽然sort()
默认从小到大排,但是它排序的过程分为比较数据和修改数据,就像冒泡排序需要把小的元素“冒泡”至“前面”,修改了这对迭代器以后对读取并比较数据没有产生任何影响,改变的是写数据时的位置,对sort()
来说,它要把小的元素放在“前面”,“前面”就是第一个迭代器表示的地方,所以使用倒序迭代器最终就产生了从大到小排序(从正常的角度)的效果。
##五、总结##
总而言之不要觉得使用迭代器很复杂,其实用了几次之后就可以轻易找到套路,当然更深层次地探究在这里就不展开了,或许今后会有新的博文。