我们已经知道可以使用下标运算符来访问string对象的字符或者vector对象的元素,还有一种更为通用的机制来实现相同的目的,这就是迭代器。
类似于指针类型,迭代器也提供了对对象的间接访问。使用迭代器可以访问某个元素,也可以从一个元素移动到另一个元素。迭代器和指针类似,可进行类比。
1.1获取迭代器有专门的类型同时拥有返回迭代器的成员。比如,这些类型都拥有名为begin和end的成员,其中begin负责返回指向第一个元素,end负责指向尾元素的下一个位置,他们返回的类型都是迭代器类型,特殊情况,如果容器为空,则begin和end返回同一个迭代器,都是尾后迭代器。
1.2标准容器迭代器的运算
*iter iter->mem // 解引用iter并获取该元素名为mem的成员,相当于(*iter).mem
++iter --iter iter1==iter2 iter1!=iter2
举例:把string对象中的第一个字母改写成大写字母,使用迭代器
string s("some string");
if(s.begin()!=s.end()){
auto it=s.begin();
(*it)=toupper(*it); // 将当前字符改成大写形式
}
1.3 将迭代器从一个位置移动到另一个位置
// 依次处理s的字符直至我们处理全部字符或者遇到空白
for(auto it=s.begin();it!=s.end()&&issapce(*it);++it)
*it=toupper(*it);
1.4泛型编程
原来使用C或者java的程序员转而使用C++之后,会对for循环使用!=而不是<感到有点奇怪。C++程序员更愿意使用!=,其原因和他们更愿意使用迭代器而不是下标原因一样:这种编程风格在标准库提供的所有容器中都有效。
1.5迭代器的类型
就像不知道string和vector的size_type类型一样,一般来说我们也不知道iterator的类型,其实也无需知道。而实际上,那些拥有迭代器的标准库类型使用iterator或者const_iterator来表示迭代器的类型:
vector<int>::iterator it; // it能读写vector<int>的元素
string::iterator it; // it能读写string的元素
vector<int>::const_iterator it; // it能只读vector<int>的元素
string::const_iterator it; // it能只读string的元素
C++11新标准中加了 cbegin() cend()函数,返回值为const_iterator类型
1.6 谨记,但凡用到for循环体的时候,都不要向迭代器所指向的容器添加元素,否则导致迭代器失效
2.1 算术运算
只要两个迭代器指向的是同一个容器的元素或者尾元素的下一个位置,就能将其进行相减,所得结果为两个迭代器的距离,其类型为difference_type的带符号整型数。因为这个距离有正有负,所以difference_type是个带符号的类型
使用迭代器运算经典的算法是二分搜索。二分搜索是从某个有序的序列中搜索给定的值。具体算法如下:
// text必须是有序序列
// beg和end是我们搜索的范围
auto beg=text.begin(),end=text.end()
auto mid=beg+(end-beg)/2; // 初始状态下中间点 不能写成(beg+end)/2 因为mid的类型是iterator而不是difference_type
while(mid!=end&&*mid=sought) { // 还有元素尚未寻找,并且我们还没有找到sought这个元素
if(*mid<sought)
beg=mid+1;
else
end=mid;
mid=beg+(end-beg)/2; // 新的中间点
}