迭代器像指针:* 取出当前元素,++ 前进一格。vector 的 begin() 指向第一个元素,end() 指向最后一个的后面,解引用 end() 非法。范围 for 在底层就是 for (it = begin; it != end; ++it),见范围 for。STL 算法也吃这一对迭代器,所以 std::sort(v.begin(), v.end()) 不必知道 v 的具体类型。本节先写出可运行的遍历,再说明类别、插入迭代器与失效。
begin 与 end
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3};
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << " "; // *it 是当前元素
}
std::cout << std::endl;
return 0;
}输出:
1 2 3 it 支持 ++、*、==。cbegin() / cend() 得到只读迭代器,不能通过 *it 改元素,适合只读遍历。
类别(能力)
| 类别 | 能力 | 示例容器 |
|---|---|---|
| 随机访问 | it + n、it[n]、< 比较 | vector、deque |
| 双向 | ++、-- | list、map、set |
| 单向 | 仅前进 | forward_list |
| 输入/输出 | 只读或只写一次 | 流迭代器 |
std::sort 要求随机访问迭代器;对 list 使用成员 sort。对数组和连续的 vector,指针也满足随机访问,可写 std::sort(arr, arr + n),见指针。
插入迭代器
算法向空 vector 写结果时,不能把 dst.begin() 当作输出位置(里面还没有格子)。std::back_inserter(dst) 每次赋值都会调用 push_back:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> src{1, 2, 3};
std::vector<int> dst;
std::copy(src.begin(), src.end(), std::back_inserter(dst));
for (int x : dst) {
std::cout << x << " ";
}
std::cout << "\n";
return 0;
}输出:
1 2 3 失效(vector 要点)
vector 扩容会换一块新内存,原先保存的迭代器、指针、引用可能全部失效。在循环里 push_back 时,不要继续使用循环开始时拿到的迭代器,改用下标或每次重新 begin。按值删除元素常用先 remove 再 erase:
v.erase(std::remove(v.begin(), v.end(), value), v.end());C++20 可用 std::erase / std::erase_if 写得更短。map 删当前元素时用 it = m.erase(it) 取得下一个仍然有效的迭代器。
本节说明了迭代器与算法、容器的关系。下一章从异常处理开始,讨论 try、throw 与 catch。