在 C++ 中,迭代器是遍历 STL 容器的重要工具。然而,初学者常在处理空容器、使用 begin() 与 end() 时犯错,导致未定义行为或程序崩溃。本文将针对这两种常见陷阱,给出详细说明和最佳实践。
1. 何谓空容器的迭代器
一个空容器的 begin() 与 end() 实际上返回相同的迭代器。对 begin() 进行解引用会导致未定义行为,因为没有元素可访问。
std::vector <int> v; // 空向量
auto it = v.begin(); // it == v.end()
*it; // ❌ 未定义行为
提示:在解引用迭代器之前,始终检查它是否等于
end()。
2. begin() 与 end() 的区别
| 语义 | 说明 |
|---|---|
begin() |
指向容器第一个元素(或空容器的结束迭代器) |
end() |
指向“后一个元素”,不指向任何有效数据,循环终止点 |
2.1 迭代器的比较
if (it != v.end()) {
// 可以安全解引用
std::cout << *it;
}
2.2 const 与非 const
const std::vector <int> cv{1, 2, 3};
auto it1 = cv.begin(); // const_iterator
auto it2 = v.begin(); // iterator
注意:
const_iterator不能解引用为非const结果。
3. 典型错误示例
3.1 忘记检查空容器
std::deque<std::string> dq;
std::string first = dq.front(); // ❌ 访问空容器导致异常
解决方案:使用 empty() 判断
if (!dq.empty()) {
std::string first = dq.front();
}
3.2 错误的 for 循环
for (auto it = v.begin(); it != v.begin(); ++it) { // 终止条件错误
// ...
}
正确应为
it != v.end()。
4. 最佳实践
- 总是使用
empty():在遍历之前判断容器是否为空。 - 使用范围基
for:大多数情况不需要手动管理迭代器。 - 避免手动解引用:除非绝对必要,尽量使用 STL 算法。
- 区分
const与非const:保持类型一致,防止隐式转换错误。 - 使用
auto:让编译器推导类型,减少手误。
5. 结语
掌握迭代器的基本规则后,C++ 编程会更稳健。空容器与 begin()/end() 的正确使用,是写出安全、高效 STL 代码的基石。祝你编码愉快!