迭代器介绍
类似于指针类型,迭代器也提供对对象的间接访问。
使用迭代器
//由编译器决定b和e的类型
//b表示v的第一个元素,e表示v尾元素的下一个位置(one past the end)
auto b = v.begin(), e = v.end();//b和e的类型相同
end成员返回的迭代器常被称作尾后迭代器(off-the-end iterator)或者简称为尾迭代器(end iterator),这样的迭代器没有实际含义,仅是个标记而已,表示我们已经处理完了容器中的所有元素。
note : (1)若容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器;
(2)一般来说,我们不清楚迭代器准确的类型,故用auto。
2.迭代器运算符,这里省略迭代运算符的列举。和指针类似,也能通过解引用迭代器来获取它所指示的元素,但试图解引用一个非法迭代器或尾后迭代器都是未被定义的行为。
string s("some string")
if(s.begin() != s.end()) //确保s非空
{
auto it = s.begin(); //
*it = toupper(*it); //将当前字符改成大写形式
}
3.将迭代器从一个元素移动到另一个元素,即使用递增(++)运算符
//依次处理s的字符直到完全处理全部字符或遇到空白
for(auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
*it = toupper(*it);//
上循环遍历没有用下标运算符,这里用的是迭代器。
note : 不能对end返回的迭代器进行递增或解引用操作。
4.关于迭代器类型,那些拥有迭代器的标准库类型使用iterator和const_iterator来表示迭代器的类型:
vector<int>::iterator it; //it能读写vector<int>的元素
string::iterator it2; //it2能读写string对象中的字符
vector<int>::const_iterator it3; //it3只能读元素,不能写元素
string::const_iterator it4; //it4只能读字符,不能写字符
note : (1)如果vector对象或string对象是一个常量,只能使用const_iterator。
(2)每个容器类定义了一个名为iterator的类型,该类型支持迭代器概念所规定的一套操作。
5.begin和end运算符。begin和end返回的具体类型由对象是否是常量决定。为了便于专门得到const_iterator类型的返回值,C++11新标准引入两个新函数,cbegin和cend,此时不管对象是否是常量,返回值都是const_iterator。
auto it3 = v.cbegin(); //it3的类型是vector<int>::const_iterator
5.结合解引用和成员访问操作。解引用迭代器可获得迭代器所指的对象,若该对象的类型是类,则有可能希望进一步访问它的成员。例如,对于一个由字符串组成的vector对象来说,想要检查其元素是否为空,令it是该vector对象的迭代器,只要检查it所指字符串是否为空:
(*it).empty() //解引用it,再调用结果对象的empty成员
为了简化上述表达式,C++语言定义了箭头运算符(->):
it->empty() //语义与上式相同
下面举例说明:
//依此输出text的每一行直到遇到第一个空白行为止
for(auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
cout << *it << endl;
6.某些对vector对象的操作会使迭代器失效。虽然vector对象可以动态增长,但也会有一些side effects。
(1)不能在范围for循环中向vector对象中添加元素
(2)任何一种可能改变vector对象容量的操作,如push_back,都会使vector对象的迭代器失效。
note : 凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。
迭代器运算(iterator arithmetic)
1.所有标准库容器都有支持递增运算和关系运算的迭代器,另外标准库类型string也有。下面举例:
iter + n //迭代器指示的新位置与原来相比向前移动了n个元素
iter - n
iter1 += n
iter1 -= n
iter1 - iter2 /*两个迭代器之间的距离,其类型为difference_type的带符号整型数,string和vector都定 义了这个类型*/>,>=,<,<= //迭代器的关系运算符
2.使用迭代器运算的一个经典算法是二分搜索。下面给出程序:
vector<string> text;
//text必须是有序的
//
auto beg = text.begin(), end = text.end();
auto mid = text.begin() + (end - beg)/2;
//
while(mid != end && *mid != sought)
{
if(sought < *mid)
end = mid;
else
begin = mid + 1;
mid = beg + (end - beg)/2;
}
NOTE : 迭代器这个名词有3种不同的含义:
(1)迭代器概念本身
(2)容器定义的迭代器类型
(3)某个迭代器对象