迭代器介绍
零.介绍
迭代器属于一种通用的机制去访问某些对象或容器里成员的值,几乎标准库里的容器都支持迭代器,而下标运算符只有几种才支持。
类似于指针,迭代器提供了对对象的简介访问。
迭代器有有效
、无效
之分。有效的迭代器指向某个元素,或者容器尾元素的下个位置;其他的所有情况都属于无效。
一.使用迭代器
1.说明
迭代器的类型同时拥有返回迭代器,比如这些类型都拥有名为begin
和end
的成员。
其中begin
负责返回第一个元素的迭代器,而end
返回的迭代器叫做尾后迭代器
。尾后
元素是不存在的,它没有什么实际含义,只是一个标记,表示已经处理了容器中的所有元素(或者用来倒着遍历?)。
如果容器为空,则begin和end返回的是同一个迭代器
2.迭代器运算符
运算符 | 作用 |
---|---|
*iter | 返回iter指向元素的引用 |
iter-mem | 等价于(*iter).mem |
++iter | 指向下一个元素 |
–iter | 指向上一个元素 |
==或!= | 判断是否(不)相等 ,如果是同一个元素或者是同一个容器的尾后,则相同;反之,不相等 |
3.元素移动
比如我们可以用递增(++)运算符来将一个元素移动到下一个元素。因为end
返回的迭代器不实际指示某个元素,所以不能对其递增或者解引用。
我们再使用标准库的迭代器的时候,尽量在循环里使用!=
或者==
,因为它们大多数里没有定义像<
这种符号,而前面两者是都定义了的,所以我们在使用迭代器的时候,要养成使用!=来进行比较、判断
4.迭代器类型
迭代器类型有两种,类似于指针和常量指针:
iterator
:能读写
const_iterator
:只能读,不能写
5.begin和end运算符
通过begin
或者end
,我们可以根据其容器的类型得到iterator
类或者const_iterator
类。
比如vector <int> a
和const vector <int> b
就会分别得到上述两个类。
可是由于我们在有些情况下,并不想需要写而只需要读,我们就可以使用C++11引入的两个运算符cbegin
或者cend
来达到对一个容器返回它的const_iterator
类的迭代器
6.结合解引用和成员访问操作
我们的箭头运算符,可以将解引用和成员访问操作结合在一起。
也就是说it->mem
和(*it).mem
表达的意思相同。
比如,假设我们有一个string
类型的容器,我们就可以通过下面操作,去调用它的方法:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <string> a{"123","123456"};
auto m = a.begin();
cout << m->size() << endl;
//或 cout << (*m).size() << endl;
}
// 返回的结果是3
当然,如果该迭代器指向的这个对象没有这个方法,就不行了,如
int main()
{
vector <int> a{10,10};
auto m = a.begin();
cout << m->size() << endl;
}
//--------------------//
error: request for member 'size' in '* m.__gnu_cxx::__normal_iterator<int*, std::vector<int> >::operator->()', which is of non-class type 'int'
cout << m->size() << endl;
7.某些对vector对象的操作会使迭代器失效
- 别在for循环中想vector对象添加元素
- 别改变vector的容量
总而言之就是一句话:别在使用迭代器的时候去改变它容器的长度
二.迭代器运算
1.说明
单个迭代器可以使用 +
-
+=
-=
这几个常见的算数运算
两个迭代器可以使用 -
>
>=
等这些符号。但前提是他们参与运算的时候必须是指向的同一个容器的元素或者尾后。
两个迭代器使用-
得到的距离是指:“右侧的迭代器向前移动多少位置就能追上左侧的迭代器”,其类型是difference_type
,它是一个带符号的整型数,因为从定义来看,这个符号可正可负。