C++ 迭代器全面详解:从概念到实战,彻底搞懂迭代器
一、什么是迭代器在 C 中迭代器Iterator是容器与算法之间的桥梁也是 STL标准模板库的核心组件之一。简单理解迭代器是面向对象版本的指针用来遍历、访问容器vector/string/map/list等中的元素。原生指针可以访问数组元素迭代器可以统一访问所有 STL 容器元素。STL 设计理念算法不依赖容器容器也不依赖算法二者全部通过迭代器交互实现代码复用。二、迭代器基本语法与使用2.1 迭代器定义格式容器类型::iterator 迭代器名;2.2 基础遍历示例以 vector 为例#include iostream #include vector using namespace std; int main() { vectorint v {10, 20, 30, 40, 50}; // 1. 定义迭代器 vectorint::iterator it; // 2. 遍历容器 // begin()指向第一个元素 // end()指向「最后一个元素的下一个位置」哨兵位不可解引用 for (it v.begin(); it ! v.end(); it) { cout *it ; // *it 解引用取迭代器指向的元素 } return 0; }输出10 20 30 40 50关键要点begin()返回指向首元素的迭代器。end()返回指向尾后位置的迭代器不能解引用。遍历条件固定it ! v.end()不建议用部分容器迭代器不支持比较大小。*it解引用获取当前元素it-成员访问对象成员。2.3 常量迭代器 const_iterator如果只读不修改容器元素推荐使用const_iterator安全性更高vectorint::const_iterator cit; for (cit v.cbegin(); cit ! v.cend(); cit) { cout *cit ; // *cit 100; // 报错常量迭代器禁止修改元素 }2.4 反向迭代器 reverse_iterator从容器末尾向前遍历vectorint::reverse_iterator rit; for (rit v.rbegin(); rit ! v.rend(); rit) { cout *rit ; }rbegin()指向最后一个元素rend()指向第一个元素的前一个位置三、迭代器的五大分类核心重点根据功能强弱、支持操作C 将迭代器分为 5 大类功能从弱到强依次升级。不同容器默认提供的迭代器类型不同直接决定了该容器能使用哪些 STL 算法。迭代器层级流程图3.1 各类迭代器详解1. 输入迭代器Input Iterator功能只读、单向遍历只能不能--只能读取一次。支持操作*it、it、/!典型场景istream_iterator流输入迭代器。2. 输出迭代器Output Iterator功能只写、单向遍历只能不能读取原有值。支持操作*it 值、it典型场景ostream_iterator、back_inserter。3. 前向迭代器Forward Iterator继承输入 输出迭代器能力单向可读写只能向后遍历。支持、读写元素、相等判断。对应容器forward_list单向链表、unordered_map/unordered_set。4. 双向迭代器Bidirectional Iterator在前向迭代器基础上支持向前 / 向后移动/--。不支持下标访问、加减数字it n。对应容器list双向链表、map、set。5. 随机访问迭代器Random Access Iterator功能最强完全等价于原生指针。支持所有操作/--、it n/it - n、[]下标、大小比较 。对应容器vector、string、deque。容器与迭代器类型对照表容器迭代器类型能否随机访问vector / string / deque随机访问迭代器✅ 支持list / map / set双向迭代器❌ 不支持forward_list / unordered_xxx前向迭代器❌ 不支持四、C11 简化写法auto 与范围 for4.1 auto 自动推导迭代器类型不用手写冗长的容器::iteratorvectorint v {1,2,3}; for (auto it v.begin(); it ! v.end(); it) { cout *it ; }4.2 范围 for 循环最简洁遍历底层本质也是迭代器编译器自动调用begin()/end()// 只读 for (int x : v) { cout x ; } // 可修改引用 for (int x : v) { x * 2; }五、迭代器失效问题高频踩坑点迭代器失效容器扩容、增删元素后原有迭代器变成野指针再次使用会程序崩溃。不同容器失效规则不同是面试 实战重点。5.1 vector 迭代器失效vector是连续内存扩容 / 插入 / 删除都会导致失效插入元素空间不足触发扩容 → 整个容器内存重新分配所有迭代器全部失效。删除元素被删除元素之后的所有迭代器失效前面的保留。错误示例崩溃代码vectorint v {1,2,3,4}; auto it v.begin() 2; v.insert(v.begin(), 100); // 扩容it 彻底失效 cout *it; // 未定义行为崩溃解决方案增删元素后重新获取迭代器。5.2 list 迭代器失效list是链表内存不连续删除当前迭代器指向元素仅当前迭代器失效其他迭代器完全有效。插入元素所有迭代器都不失效。5.3 map /set 迭代器失效基于红黑树插入元素所有迭代器有效。删除元素仅被删除节点的迭代器失效其余不变。六、迭代器配合 STL 算法使用STL 算法全部依靠迭代器传参格式统一算法名(起始迭代器, 结束迭代器, ...)。示例#include algorithm vectorint v {5, 2, 9, 1}; // 排序[begin, end) 左闭右开区间 sort(v.begin(), v.end()); // 查找元素 auto pos find(v.begin(), v.end(), 9); if (pos ! v.end()) { cout 找到元素 *pos endl; }所有算法遵循左闭右开区间[begin, end)这是 STL 统一规范。七、手写简易迭代器理解底层原理为了彻底弄懂我们实现一个极简版数组容器 自定义迭代器模拟 STL 底层逻辑// 自定义简易容器 templatetypename T class MyVector { private: T* _data; size_t _size; public: // 自定义迭代器本质就是封装指针 class Iterator { private: T* _ptr; public: Iterator(T* p) : _ptr(p) {} // 解引用 T operator*() { return *_ptr; } // 前置 Iterator operator() { _ptr; return *this; } // 不等判断 bool operator!(const Iterator other) { return _ptr ! other._ptr; } }; MyVector(T* arr, size_t n) { _size n; _data new T[n]; for (size_t i 0; i n; i) _data[i] arr[i]; } ~MyVector() { delete[] _data; } Iterator begin() { return Iterator(_data); } Iterator end() { return Iterator(_data _size); } }; // 测试 int main() { int arr[] {100, 200, 300}; MyVectorint mv(arr, 3); for (auto it mv.begin(); it ! mv.end(); it) { cout *it ; } return 0; }STL 迭代器底层绝大多数就是对原生指针的封装重载了*、、!等运算符对外提供统一访问接口。