迭代器是一个 可遍历 STL 容器全部或部分元素的对象,用来表现容器中某一个位置,
基本操作
-
operator* 返回当前位置的元素,如果当前位置的元素存在,也可以使用 -> 获取他们
-
operator++ 令迭代器前进至下一个元素,大多数迭代器也可以使用 operator-- 前进一个元素
-
operator==或!= 判断两个迭代器是否指向同一个地址,
-
operator= 迭代器赋值
这些操作运用pointer操作寻常的arrya 元素时是保持一致的,差别在于迭代器是所谓的 smart pointer ,具有遍历复杂数据结构的能力,其遍历机制取决于其所遍历的数据结构,因此每一种容器都必须有自己的迭代器
所有的容器类都提供一些基本的成员函数,让我们可以获取到迭代器并以之遍历所有的元素,这些函数重要的是 begin()容器的起点,指向第一个元素的位置,end() 指向容器的终点,他的位置在容器最后一个数据后的下一个位置,如实begin 和 end 就形成了一个半开区间,关系图大致如下
这种关系有两个优点
1: 为遍历 loop 结束提供一个简单的逻辑判断,只要未到达 end, loop 就可以继续进行
2:不必对空区间采取特殊处理手法,空区间的begin 就等价于 end
下面提供一个简单的例子
int tsm_iterator(){
list<char> lis;
for (int i = 'a'; i <='z'; ++i) {
lis.push_back(i);
}
list<char>::const_iterator iterator;
for (iterator=lis.begin();iterator!=lis.end();++iterator) {
cout<< *iterator<<endl;
}
}
结果:
D:\CWorkSpace\tsmTest\cmake-build-debug\tsmTest.exe
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
Process finished with exit code 0
任何容器都定义了两种迭代器类型
1: container::interator 以读写的模式遍历容器
2: container::const_interator 以只读的模式遍历容器
这里还是list 为例简单的看一下 list 中 的源码
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class list : protected _List_base<_Tp, _Alloc>
{
typedef _List_iterator<_Tp> iterator;
typedef _List_const_iterator<_Tp> const_iterator;
}
那么就意味着,在遍历过程中,如果你获取的是 const_iterator ,那么在整个循环工程中你是无法对 *const_iterator 做更改了,但是如果你获取到了 iterator ,如果存入的数据是一个非 const 的数据,那么在遍历过程中就可以使用 *iterator 对数据做更改,
++iterator vs iterator++
注意 在遍历过程中尽量使用前置式递增,而避免使用后置式递增,因为前者的效率更高,原因是后者必须保存一个临时变量,来返回当前的位置,
所以在使用迭代器的遍历过程中尽量使用 ++iterator ,不要使用 iterator++ ,当然这里的推荐使用++iterator并不是以代码的健壮性和易读性来换取的,只是这种使用方式会带来些许性能上的提升
cbegin() 与 cend()
在C++ 11 开始引入的auto 的概念,他给我们带了非常多的好处,还是前面的list 为例,我们可以使用 auto 来简化代码,如下
int tsm_iterator(){
list<char> lis;
for (int i = 'a'; i <='z'; ++i) {
lis.push_back(i);
}
for (auto it=lis.begin();it!=lis.end();++it){
cout<< *it<<endl;
}
}
相较于之前的 list::iterator 确实是简化了不少,而且如果在后期数据类型发生改变的情况,这里的代码也是适用的,但是使用 auto 也带来了一定的风险,那就是 auto 会使迭代器丧失常量性, 也就是 auto it=lis.begin()获取的是一个非常量的迭代器,为了确保在整个过程中仍然能使用 常量迭代器,自C++ 11 开始容器提供了常量迭代器 cbegin() 与 cend(),他们返回的类型是 const_iterator
Range-Based for vs 迭代器
在遍历 STL 容器我们还可以使用更为便捷的方法, 还是以上面的list为例 方式如下
for (auto item:lis){
}
他被翻译成迭代器的版本如下
for (auto it=lis.begin();it!=lis.end();++it){
auto item=*it;
}