3.4 迭代器
我们可以通过下标运算符[]访问string对象的字符或vector对象的元素,但还有一种更通用的机制也可以实现:那就是 迭代器(iterator) 所有标准容器都可以使用迭代器,但是其中只有少数几种同时支持下标运算符。
类似于指针类型,迭代器也提供对对象的间接访问。但是迭代器也分为有效迭代器和无效迭代器。有效迭代器:指向某个元素或者指向容器中尾元素的下一个位置。无效迭代器:反之,都是无效迭代器。
3.4.1使用迭代器
和指针不一样:获取迭代器不是使用取值运算符&,有迭代器的类型同时返回迭代器的成员。
auto b = v.begin(); //返回指向v中第一个元素(或第一个字符)的迭代器
auto e =v.end(); //返回指向v中“尾部元素的下一个位置”的迭代器
注: end()函数返回的迭代器指向容器中的一个根本不存在的“尾后”元素,这样的迭代器其实没什么实际含义,只不过为了做标记而已。 end()函数返回的的迭代器常称作:“尾后迭代器”
特殊情况下:如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。
迭代器运算符
运算符 | 解释 |
---|---|
iter->mem | 解引用iter并获取该元素的名为mem的成员,等价于 (*item).men |
*iter | 返回迭代器iter所指元素的引用 |
++iter | 令iter指示容器中下一个元素 |
–iter | 令iter指示容器中上一个元素 |
iter1 ==iter2 iter1 != iter2 | 判断两个迭代器是否相等(不等),如果两个迭代器指向 同一个元素或者他们是同一个容器的尾后迭代器,则相等, 反之,不等。 |
//依次处理s的字符,直到处理完全部字符或者遇到空白
for(auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
{
*it = toupper(*it); //将当前字符改写成大写
}
//因为end返回的迭代器并不实际指示某个元素,所以不能对其进行递增或解引用的操作
//注意for循环中使用的是 != 而不是 <
/*因为之前说过,只有string和vector等一些标准库类型有下标运算符,而非全都如此。与之类似,所有标准库容器的迭代器都定义了 == 和 !=,但是他们中的大多数都没定义 < 运算符。因此只要我们养成使用迭代器和 !=的习惯,就不用太在意到底用哪种容器类型*/
迭代器类型
- iterator
- const_iterator
vector<int>::iterator it; //it能读写vector<int>的元素
string::iterator it2; //it2能读写string对象中的字符
vector<int>::const_iterator it3; //it3只能读元素,不能写元素
string::const_iterator it; //it4只能读字符,不能写字符
注:
- 如果vector对象或者string对象是一个常量,只能使用 const_iterator
- 如果vectror对象或者string对象不是一个常量,那么即可以使用iterator
也可以使用const_iterator
begin和end运算符
begin 和 end 返回的具体类型由对象是不是常量决定
- 对象是常量,返回const_iterator
- 对象是变量,返回iterator
vector<int> v;
const vector<int>cv;
auto it1 = v.begin(); //it1的类型是vector<int>::iterator
auto it2 = cv.begin(); //it2的类型是vector<int>::const_iterator
然而有时候,如果对象只需要都操作,不需要写操作,那我们会好使用常量类型。
C++11引入:cbegin 和 cend
vector<int> v; //对象不是常量。让它返回常量类型
auto it1 = v.cbegin(); //it1的类型是vector<int>::const_iterator
某些对vector对象的操作会使迭代器失效
- 不能在范围for循环中向vector对象添加元素
- 任何一种可能改变vector对象容量的操作,比如
push_back
都会使vector对象的迭代器失效。
但凡使用了迭代器的循环体,都不要向迭代器所属的容器中添加元素
3.4.2 迭代器运算
所有的标准库容器都有支持递增运算的迭代器,类似的,也能用 ==和 !=对任意标准库类型的两个有效迭代器进行比较
vector和string 迭代器支持的运算 | 解释 |
---|---|
iter + n | 迭代器加上一个整数仍得一个迭代器,向前移动了若干个元素。结果 迭代器或者指向容器中的一个元素,或者指向容器尾元素的下一个位置 |
iter - n | 迭代器减去一个整数仍得一个迭代器,向前移动了若干个元素。结果 迭代器或者指向容器中的一个元素,或者指向容器尾元素的下一个位置 |
iter1 += n | iter1 = iter1 + n |
iter1 -= n | iter1 = iter1 - n |
iter1 - iter2 | 两个迭代器相减的结果是它们之间的距离 |
< ,>= ,<,<= |
auto mid = vi.begin() + vi.size()/2;
//计算得到会接近vi中间元素的一个迭代器
两个迭代器的距离:指的是 右侧的迭代器向前移动多少个位置就能追上左侧的迭代器。
类型: difference_type
的带符号整数,因为这个距离可正可负。
string 和 vector都定义了 difference_type