🍓迭代器
2022-5-1
| 2023-8-2
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property

 
可以使用下标运算符来访问string对象的字符或vector对象的元素,还有另外一种更通用的机制也可以实现同样的目的,这就是迭代器(iterator)。
C++中更常用的访问容器中的元素方式是通过迭代器,因为有些容器无法通过下标来访问的,这种容器是不可随机访问的。所有容器都可以通过迭代器来访问元素。虽然string不是容器,但是string支持很多容器的操作,包括迭代器和下标访问。
 
迭代器是对语言中的指针的一种抽象和模拟,用来间接访问元素。与指针一样,通过迭代器可以从一个元素移动到另一个元素,可以通过解引用返回元素的引用,可以通过箭头符调用其成员函数。迭代器也有非法迭代器(invalid iterator)只有确实指向元素或者指向尾元素的下一个位置才是合法迭代器,其它所有迭代器都是非法的。
 

迭代器

和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员。比如,这些类型都拥有名为beginend的成员:
  • begin成员负责返回指向第一个元素(或第一个字符)的迭代器
  • end成员则负责返回指向容器(或string对象)“尾元素的下一位置”的迭代器,指示的是容器的一个本不存在的“尾后”元素。这样的迭代器没什么实际含义,仅是个标记而已,表示已经处理完了容器中的所有元素。
end成员返回的迭代器通常被称作尾后迭代器或者简称为尾迭代器。如果容器为空,则beginend返回的是同一个迭代器,都是尾后迭代器。
 

迭代器运算符

迭代器只支持比较少的操作,只有支持随机访问的容器支持其迭代器与整数的加减法来用快速步进迭代器,以下是所有迭代器都支持的操作:
notion image
  • *iter解引用迭代器,返回所指向的元素的引用,不能对尾后迭代器进行解引用。解引用一个非法迭代器和尾后迭代器的行为是未定义的
  • iter->mem 直接调用迭代器所指向元素的成员函数mem,与 (*iter).mem 完全一致
  • ++iter 自增,使其指向下一个元素,不应该对尾后迭代器进行自增操作
  • --iter 自减,使其指向前一个元素
  • iter1 == iter2 判断两个迭代器是否相等,只有指向同一个容器中的同一个元素(尾后元素也是一个元素)的迭代器才会相等
  • iter1 != iter2 判断两个迭代器不相等
 
C++常用的比较迭代器的方式是 != 而不是< ,其原因在于很多迭代器根本没有<操作,为了支持所有迭代器,通用的做法是用!=来比较:
 

迭代器类型

通常不知道也不需要知道迭代器的确切类型,标准库为每个容器类定义两个迭代器iterator 和 const_iterator 。
所有的const对象返回的的迭代器都是const_iteratorconst迭代器和const指针一样不能用于改变所指向的元素值。非const对象可以通过cbegincend成员函数返回const迭代器。
迭代器是一组概念相关的类型,它们都支持一类操作,并且行为是类似的。同样容器也是一组相关的类型。
 

begin和end运算符

begin和 end返回的迭代器具体类型由对象是否是常量决定,如果对象是常量,则返回 const_iterator;如果对象不是常量,则返回 iterator
C++11新增了cbegincend函数,不论vectorstring对象是否为常量,都返回const_iterator迭代器
 
某些对vector对象的操作会使迭代器失效
不能在范围for循环中向vector对象添加元素。任何可能改变容器对象容量的操作(如push_back)会使得之前返回的迭代器失效。所以,不要在使用迭代器的循环中改变vector的长度。
 

结合解引用和成员访问

解引用迭代器可获得迭代器所指的对象,如果该对象的类型恰好是类,可以进一步访问它的成员。例如, 一个由字符串组成vector对象,想检查其元素是否为空,令it是该vector对象的迭代器, 检查it所指字符串是否为空:
为了简化表达式,C++定义了箭头运算符->,把解引用和成员访问两个操作结合在一起,iter>mem(*iter).mem完全一致:
 

迭代器算术运算

只有少部分容器支持迭代器的算术运算,支持算术运算的容器通常是可随机访问的容器,意思是可以在任何时刻访问容器中的任意元素,而其它容器则必须一个一个向前移动访问。这种区别就跟数组与链表的区别。
迭代器算术运算指的是对迭代器加减整数返回的是一个跨越若干元素的另外一个迭代器,加则向后移动,减则向前移动。两个迭代器相减返回两者之间的距离。这样的迭代器通常还支持关系运算,可以比较大小,而其它的迭代器则不可以。
notion image
iter1 - iter2 的结果类型是各自容器的difference_type,如:vector<int> difference_type,这是一个有符号整数。
 
使用迭代器完成了二分搜索:
 
  • C++
  • 标准库类型vector数组
    目录