接触 STL 的容器有一段时间了,现在来聊一聊迭代器的问题。
我第一个接触的容器是 vector,当时遍历容器的写法就是简单的迭代循环。
代码是这样写的:
|
后来看到别人的写法是这样的:
|
觉得既然 STL 既然内置了 iterator,应该有它自己的优势,虽然这两种写法的时间复杂度都是 O(n)。
那么它们的具体区别是什么呢?在我闲逛 stackoverflow 时看到了相关的讨论,这两种方式在遍历 vector 时并无区别,但是第一种方法却不一定适用于其它容器,例如 map,而且后者也易于理解,从维护性,复用性等角度来看都是后者更具备优势。
在 STL 中还有反向迭代器,可以反序遍历容器,像这样:
|
这里反向迭代器将 ++ 与 -- 的含义反了过来,++ 访问前一个元素,而 -- 访问后一个元素。
但是为什么不像下面这样遍历呢?
|
有这种想法的人(比如我)运行一下就知道了,结果并不是想象中的那样,因为 v.end() 返回指向当前对象中 末尾之后( Past-the-end) 的元素的迭代器。一图胜千言:
|
为什么不将 end() 指向最后一个元素呢?这个问题有点类似为什么数组标号是从 0 开始的,之所以指向末尾之后的元素原因有很多,我举几个例子:
|
这样不仅不优雅,假设容器是空的,begin() 与 end() 的顺序也会令人费解。
|
所有参数与迭代器相关的函数都要补上 +1,代码变得丑陋。
再比如,如果在容器内未找到元素之后返回的结果要改为 end()+1 而不是原来的 end()。
还想了解更多原因的话,请看 Dijkstra 爷爷的原文:Why numbering should start at zero
如果你非常希望通过 begin() 和 end() 进行反向迭代也未尝不可,不过我不会告诉你写法,放弃这种方法吧。
最后,强制将正向迭代器反向不一定能得到想要的结果:
|
第一个输出的结果是错的,第二个与第三个的结果也不一样,所以请不要乱使用迭代器。
参考链接:
- Why use iterators instead of array indices?
- Why are Standard iterator ranges [begin, end) instead of [begin, end]?
- Use a regular iterator to iterate backwards, or struggle with reverse_iterator?
文档信息
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
本文链接:www.snovey.com/2016/09/STL-iterator.html