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:
| |
避免这类问题的最简单的方法是减少混用不同类型的迭代器的机会。
支付宝
微信