迭代器有有效和无效之分,这一点和指针差不多。有效的迭代器或者指向某个元素,或者指向容器中尾元素的下一位置,其它情况都属于无效

使用迭代器

1
2
// b表示v的第一个元素,e表示v尾元素的下一位置
auto b = v.begin(), e = v.end(); // b和e的类型相同

end成员则负责返回指向容器(或string对象)“尾元素的下一位置(one past the end)”的迭代器,也就是说,该迭代器指示的是容器的一个本不存在的“尾后( off the end)”元素。这样的迭代器没什么实际含义,仅是个标记而已,表示我们已经处理完了容器中的所有元素。end成员返回的迭代器常被称作尾后迭代器( off-the-end iterator) 或者简称为尾迭代器(end iterator)。 特殊情况下如果容器为空,则begin和end返回的是同一个迭代器。

迭代运算符

1
2
3
4
5
6
*iter           // 返回迭代器iter所指无素的引用
iter- >mem // 解引用iter并获取该元素的名为mem的成员,等价于(*iter) . mem
++iter // 令iter指示容器中的下一个元素
--iter // 令iter指示容器中的上一个元素
iterl == iter2 // 判断两个迭代器是否相等(不相等),如果两个迭代器指示的是同一个元
iter1 != iter2 // 素或者它们是同一个容器的尾后迭代器,则相等;反之,不相等

例:将string对象第一个字母改为大写形式

1
2
3
4
5
6
string s("hello string");
if (s.begin() != s.end()) // 确保s非空
{
auto it = s.begin();
*it = toupper(*it);
}

将迭代器从一个元素移动到另外一个元素

1
2
3
// 依次处理s的字符直至我们处理完全部字符或者遇到空白
for (auto it = s.begin(); it != s.end() && != isspace(*it); ++it)
*it = toupper(*it);

迭代器类型

1
2
3
4
5
vector<int>::iterator it;           // 能读能写
string::iterator it2;

vector<int>::const_iterator it3; // 只能读,不能写
string::const_iterator it4;

begin和end运算符

cbegin与cend

1
2
3
4
5
vector<int> v;
const vector<int> cv;
auto it1 = v.begin(); // it1是vector<int>::iterator
auto it2 = v.begin(); // it2是vector<int>::const_iterator
auto it3 = v.cbegin(); // 使用cbegin()无论vector对象本身是否是常量,返回值都是const_iterator

结合解引用和成员访问的操作

1
2
3
// 两种操作等价
(*it).empty()
it->empty()

但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。

迭代器运算

例:二分搜索

1
2
3
4
5
6
7
8
9
10
11
12
// text 必须有序
// beg 和 end 表示我们搜索的范围
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
beg = mid + 1;
mid = beg + (end - beg) / 2;
}