Effective STL [26] | 尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator
4种迭代器
每个标准容器类都提供4种迭代器类型:iterator
,const_iterator
,reverse_iterator
和const_reverse_iterator
对于container<T>
而言,iterator
的作用相当于T*
,而const_iterator
则相当于const T*
。
增加一个iterator
或者const_iterator
可以在一个从容器开头趋向尾部的遍历中让你移动到容器的下一个元素。
reverse_iterator
与const_reverse_iterator
同样相当于对应的T
和const T
,所不同的是,增加reverse_iterator
或者const_reverse_iterator
会在从尾到头的遍历中让你移动到容器的下一个元素。
vector的insert和erase的样式
|
|
这些方法只接受iterator
类型的参数,而不是const_iterator
、reverse_iterator
或const_reverse_iterator
。总是iterator
。
迭代器之间存在的转换关系
图中显示了从iterator
到const_iterator
、从iterator
到reverse_iterator
和从reverse_iterator
到const_reverse_iterator
可以进行隐式转换。
并且,reverse_iterator
可以通过调用其base成员函数
转换为iterator
。const_reverse_iterator
也可以类似地通过base
转换成为const_iterator
。
通过base得到的也许并非你所期待的iterator。
而且,没有办法从一个const_iterator转换得到一个iterator,也无法从const_reverse_iterator得到reverse_iterator。
所以,当你需要指出插入位置或删除的元素时,const迭代器几乎没有用。
尽量使用iterator取代const或者reverse类型的迭代器
insert
和erase
的一些版本要求iterator
。如果你需要调用这些函数,你就必须产生iterator
,而不能用const
或reverse iterators
。不可能把
const_iterator
隐式转换成iterator
。从一个const_iterator
产生一个iterator
的技术并不普遍适用,而且不保证高效。从
reverse_iterator
转换而来的iterator
在转换之后可能需要相应的调整。
iterator
与reverse_iterator
之间的选择显而易见——依赖于从前到后或从后到前的遍历。
迭代器比较
当在iterator
和const_iterator
之间作选择的时候,你有更充分的理由选择iterator
,即使const_iterator
同样可行而且即使你并不需要调用容器类的任何成员函数。其中的令人讨厌的原因包括iterator
与const_iterator
之间的比较:
|
|
唯一的变化是等号的一边的类型是iterator
,而另一边的类型是const_iterator
。
因为iterator
应该在比较之前隐式的转换成const_iterator
,真正的比较应该在两个const_iterator
之间进行。
如果一些实现将const_iterator
的operator==
作为const_iterator
的一个成员函数而不是非成员函数。
而问题的解决之道显得非常有趣:只要像这样交换两个iterator
的位置:
|
|
迭代器混用
不仅是比较是否相等,只要你在同一个表达式中混用iterator
和const_iterator
(或者reverse_iterator
和const_reverse_iterator
),这样的问题就可能会出现:
|
|
如果迭代器的类型不同,你的正确的代码可能会被错误地拒绝。
本例中最简单的解决方法是通过一个(安全的)映射把iterator转换为const_iterator:
|
|
避免这类问题的最简单的方法是减少混用不同类型的迭代器的机会。