C++ 迭代器:原理 + 使用方法
一、迭代器是什么?(原理)
迭代器 = 智能指针 = 容器的"通用遍历工具"
你可以把它理解成:
- 数组的指针
- 链表的节点指针
- 字符串的字符指针
- 甚至文件、流、数据库的"游标"
迭代器统一了所有容器的遍历方式
不管底层是数组、链表、树、哈希表,你遍历的写法都一样:
cpp
for (迭代器 it = 容器.begin(); it != 容器.end(); ++it)
使用 *it
这就是迭代器的核心价值 :屏蔽底层差异,提供统一接口。
二、迭代器的原理
迭代器就是一个对象,它知道:
- 当前在哪(指向某个元素)
- 怎么走到下一个(++it)
- 怎么取出数据(*it)
- 什么时候结束(it == end())
它本质就是对指针的封装,让指针行为更安全、更通用。
三、迭代器长什么样?
这就是迭代器的灵魂结构:
cpp
template <typename T>
struct iterator {
T* _ptr; // 指向元素
T& operator*() { // 取内容
return *_ptr;
}
iterator& operator++() { // 往前走
_ptr++;
return *this;
}
bool operator!=(const iterator& other) {
return _ptr != other._ptr;
}
};
是不是超级简单?
迭代器 = 指针 + 三个运算符
四、迭代器的使用方法(最常用 4 种)
1. 最标准遍历(所有容器通用)
cpp
vector<int> v = {1,2,3};
for (auto it = v.begin(); it != v.end(); ++it) {
cout << *it << endl;
}
规则:
begin()→ 指向第一个元素end()→ 指向最后一个元素的下一个位置(不存数据)++it比it++快(推荐用前置)- 判断用
!=不用<(链表不能用 <)
2. C++11 范围for(最简单)
底层自动调用迭代器:
cpp
for (auto x : v) { ... }
等价于:
cpp
for (auto it = v.begin(); it != v.end(); ++it)
auto x = *it;
3. 只读遍历(const_iterator)
不想修改数据时用,更安全:
cpp
for (auto it = v.cbegin(); it != v.cend(); ++it)
或:
cpp
for (const auto& x : v)
4. 反向遍历(reverse_iterator)
从后往前:
cpp
for (auto it = v.rbegin(); it != v.rend(); ++it)
五、迭代器的 5 种分类(必须懂)
按功能强弱排序:
- 输入迭代器:只读一次(istream)
- 输出迭代器:只写一次(ostream)
- 正向迭代器:只能 ++(单向链表)
- 双向迭代器:++ 和 --(list、set、map)
- 随机访问迭代器:最强,支持 +、-、\[\]、<(vector、string、deque)
越往下功能越强!
六、迭代器常用操作
cpp
*it 取元素
it-> 取成员(对象用)
++it 下一个
--it 上一个(双向迭代器以上)
it += n 跳 n 个(随机访问)
it - it 距离(随机访问)
it == it
it != it
七、为什么要用迭代器?
-
统一遍历语法
数组、链表、map、set 遍历写法一样
-
不暴露容器内部结构
你不用知道内部是数组还是链表,迭代器帮你搞定
-
配合 STL 算法
sort、find、for_each 全都靠迭代器
cpp
sort(v.begin(), v.end());
find(v.begin(), v.end(), 10);
总结
迭代器原理
迭代器是封装了指针的对象,提供统一遍历接口。
迭代器使用
cpp
for (auto it = 容器.begin(); it != 容器.end(); ++it)
*it 访问元素
核心运算符(必须实现)
*it取元素++it下一个!=判断结束
C++ 手写迭代器(练手版)
练手写迭代器,最简单的方式是给一个自定义数组/容器写一个「正向迭代器」 ,不用搞复杂功能,先把迭代器必须的接口、类型、运算符写对就行。
目标
我们手写一个:
- 自定义容器
MyVector(简单动态数组) - 给它写一个自定义迭代器
MyIterator - 支持:
*it、++it、==、!=、-> - 支持 C++11 范围for
for(auto x : vec)
手写一个迭代器以及自定义容器类
cpp
#include<iostream>
#include<cstring>
using namespace std;
template<typename T>
struct MyIterator
{
using value_type = T;
using pointer = T*;
using reference = T&;
using difference_type = ptrdiff_t;
using iterator_category = random_access_iterator_tag;
pointer _ptr;
MyIterator(pointer p = nullptr) : _ptr(p) {}
//解引用
reference operator*(){
return *_ptr;
}
//成员访问 it->xxx
pointer operator->(){
return _ptr;
}
//前置自增 ++it
MyIterator operator++(){
_ptr++;
return *this;
}
// 后置自增 it++
MyIterator operator++(int) {
MyIterator temp = *this;
_ptr++;
return temp;
}
bool operator== (const MyIterator& other) const{
return _ptr == other._ptr;
}
// 判不等 it1 != it2
bool operator!=(const MyIterator& other) const{
return !(*this == other);
}
};
/**
* 自定义容器:搭配迭代器使用
*/
template<typename T>
class MyVector
{
private:
T* _data;
int _size;
int _capacity;
public:
// 给容器暴露迭代器类型
using iterator = MyIterator<T>;
// 构造函数
MyVector(): _data(nullptr), _size(0), _capacity(0){}
// 添加元素
void push_back(const T& val){
//当容器没有空间时
if(_size == _capacity){
//当容量不足时,按指数级预先分配空间
int newCap = (_capacity == 0) ? 1 : _capacity * 2;
T* newData = new T[newCap];
if(_data){
//把之前的数据搬到新的空间上,这里用循环拷贝
for (int i = 0; i < _size; ++i) {
newData[i] = _data[i];
}
delete[] _data;
}
_data = newData;
_capacity = newCap;
}
_data[_size++] = val;
}
// ======================================
// 容器必须提供:begin() + end()
// ======================================
iterator begin(){
return iterator(_data);
}
iterator end(){
return iterator(_data + _size);
}
int size() const{
return _size;
}
};
int main() {
MyVector<int> vec;
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
// 1. 普通迭代器遍历
cout << "iterator: ";
for (MyVector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 2. C++11 范围for(依赖正确的 begin/end/*/++/!=)
cout << "range-for: ";
for (auto x : vec) {
cout << x << " ";
}
cout << endl;
return 0;
}
运行输出:
iterator: 10 20 30
range-for: 10 20 30
手写一个双向迭代器以及自定义容器类
双向迭代器 = 支持 ++it(往后) + --it(往前)
最经典的场景:链表(list),因为链表不能像数组那样随机访问,只能一步步前后跳。
核心规则(双向迭代器)
- 必须实现:*、->、++、--、==、!=
- 必须写 5 个标准类型别名
- 迭代器类型标记:bidirectional_iterator_tag
- 容器必须提供 begin()、end()
cpp
#include <iostream>
using namespace std;
// 链表节点结构
template <typename T>
struct Node {
T val;
Node* prev; // 前驱(支持 --)
Node* next; // 后继(支持 ++)
Node(T v) : val(v), prev(nullptr), next(nullptr) {}
};
// ==============================
// 手写 双向迭代器
// ==============================
template <typename T>
struct MyListIterator {
// ==============================
// 1. 必须写的 5 个标准类型
// ==============================
using value_type = T;
using pointer = T*;
using reference = T&;
using difference_type = ptrdiff_t;
using iterator_category = bidirectional_iterator_tag; // 双向迭代器!
// 迭代器持有:当前节点指针
Node<T>* _node;
// 构造
MyListIterator(Node<T>* p = nullptr) : _node(p) {}
// ==============================
// 2. 核心接口
// ==============================
// 解引用
reference operator*() const {
return _node->val;
}
// 成员访问
pointer operator->() const {
return &(_node->val);
}
// 前置 ++:往后走
MyListIterator& operator++() {
_node = _node->next;
return *this;
}
// 前置 --:往前走(双向迭代器关键!)
MyListIterator& operator--() {
_node = _node->prev;
return *this;
}
// 判断相等
bool operator==(const MyListIterator& other) const {
return _node == other._node;
}
bool operator!=(const MyListIterator& other) const {
return !(*this == other);
}
};
// ==============================
// 简易链表容器(配合双向迭代器)
// ==============================
template <typename T>
class MyList {
private:
Node<T>* _head;
Node<T>* _tail;
public:
// 暴露迭代器类型
using iterator = MyListIterator<T>;
MyList() : _head(new Node<T>(0)), _tail(new Node<T>(0)) {
_head->next = _tail;
_tail->prev = _head;
}
// 尾插
void push_back(const T& val) {
Node<T>* newNode = new Node<T>(val);
Node<T>* prev = _tail->prev;
prev->next = newNode;
newNode->prev = prev;
newNode->next = _tail;
_tail->prev = newNode;
}
// ==============================
// 容器必须提供 begin / end
// ==============================
iterator begin() {
return iterator(_head->next);
}
iterator end() {
return iterator(_tail);
}
};
// ==============================
// 测试双向迭代器
// ==============================
int main() {
MyList<int> lst;
lst.push_back(10);
lst.push_back(20);
lst.push_back(30);
// 1. 正向遍历(++)
cout << "正向 ++: ";
for (auto it = lst.begin(); it != lst.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 2. 反向遍历(--)【双向迭代器特色】
cout << "反向 --: ";
auto it = lst.end();
--it; // 从最后一个元素开始
while (it != lst.begin()) {
cout << *it << " ";
--it;
}
cout << *it << endl;
return 0;
}
手写一个只读迭代器
只读迭代器
- 只能 *it 读,不能修改元素
- 返回 const T&、const T*
随机访问迭代器
- 支持 ++、--
- 支持 it + n、it - n、itn
- 支持 <、>、<=、>=
- 类型标记:random_access_iterator_tag
cpp
#include<iostream>
using namespace std;
template <typename T>
struct MyConstRandomIterator{
// 1.标准五种类型
using value_type = T;
using pointer = const T*;
using referece = const T&;
using difference_type = ptrdiff_t;
using iterator_category = random_access_iterator_tag;
// 核心:持有指针
pointer _ptr;
//构造
MyConstRandomIterator(const T* p = nullptr) : _ptr(p){}
// ==============================
// 2. 基础接口(只读)
// ==============================
referece operator*() const{
return *_ptr;
}
pointer operator->() const{
return _ptr;
}
//前置++
MyConstRandomIterator& operator++(){
_ptr++;
return *this;
}
//后置++
MyConstRandomIterator operator++(int){
auto tmp = *this;
_ptr++;
return tmp;
}
//前置--
MyConstRandomIterator& operator--(){
_ptr--;
return *this;
}
//后置--
MyConstRandomIterator operator--(int){
auto tmp = *this;
_ptr--;
return tmp;
}
// ==============================
// 3. 随机访问核心功能
// ==============================
// 前进 n 步
MyConstRandomIterator& operator+=(difference_type n){
_ptr += n;
return *this;
}
// 后退 n 步
MyConstRandomIterator& operator-=(difference_type n) {
_ptr -= n;
return *this;
}
// it + n
MyConstRandomIterator operator+(difference_type n)const{
return MyConstRandomIterator(_ptr + n);
}
// it - n
MyConstRandomIterator operator-(difference_type n) const{
return MyConstRandomIterator(_ptr - n);
}
// 两个迭代器相差多少个元素
difference_type operator-(const MyConstRandomIterator& other) const{
return _ptr - other._ptr;
}
// 下标 访问 it[n]
referece operator[](difference_type n) const{
return _ptr[n];
}
// ==============================
// 4. 比较运算符(随机访问需要)
// =============================
bool operator==(const MyConstRandomIterator& other) const{
return _ptr==other._ptr;
}
bool operator!=(const MyConstRandomIterator& other) const{
return !(*this==other);
}
bool operator<(const MyConstRandomIterator& other) const {
return _ptr < other._ptr;
}
bool operator>(const MyConstRandomIterator& other) const {
return _ptr > other._ptr;
}
bool operator<=(const MyConstRandomIterator& other) const {
return _ptr <= other._ptr;
}
bool operator>=(const MyConstRandomIterator& other) const {
return _ptr >= other._ptr;
}
};
template<typename T>
class MyArray{
private:
T* _data;
int _size;
public:
using const_iterator = MyConstRandomIterator<T>;
MyArray(const T* arr, int n){
_size = n;
_data = new T[n];
for (int i = 0; i < n; ++i)
_data[i] = arr[i];
}
~MyArray(){
delete []_data;
}
int size(){
return _size;
}
const_iterator begin() const{
return const_iterator(_data);
}
const_iterator end() const{
return const_iterator(_data + _size);
}
};
// ==============================
// 测试:只读 + 随机访问
// ==============================
int main() {
int arr[] = {10, 20, 30, 40, 50};
MyArray<int> ma(arr, 5);
// 1. 普通遍历
cout << "遍历: ";
for (auto it = ma.begin(); it != ma.end(); ++it) {
cout << *it << " ";
// *it = 100; ❌ 报错!只读迭代器不能修改
}
cout << endl;
// 2. 随机访问 it[n]
cout << "it[2] = " << ma.begin()[2] << endl;
// 3. it + 3
auto it = ma.begin() + 3;
cout << "begin + 3 = " << *it << endl;
// 4. 比较大小
if (it > ma.begin())
cout << "it 在 begin 后面" << endl;
return 0;
}
你必须掌握的迭代器核心
手写迭代器只需要做好这几件事:
1. 必须写 5 个标准类型别名
cpp
using value_type = T;
using pointer = T*;
using reference = T&;
using difference_type = ptrdiff_t;
using iterator_category = random_access_iterator_tag;
不写会导致:不能和 STL 算法兼容、范围for可能报错。
2. 迭代器内部存一个指针
几乎所有手写迭代器都是:包一层指针
cpp
pointer _ptr;
3. 必须实现 4 个核心运算符
operator*()→ 解引用operator->()→ 成员访问operator++()→ 移动到下一个元素operator== / !=→ 判断是否结束
4. 容器必须提供 begin() 和 end()
这是迭代器能用的前提:
cpp
iterator begin() { return iterator(_data); }
iterator end() { return iterator(_data + _size); }
5. 容器必须写 using iterator = 你的迭代器
让外部能拿到迭代器类型:
cpp
using iterator = MyIterator<T>;
6. 范围for 自动依赖
只要你写对:
begin()end()*it++itit != it
范围for for(auto x : container) 自动生效!
你可以一步步扩展练手(由浅到深)
你可以按这个顺序加功能,逐步变强:
- 先跑通上面代码 ✅
- 加
operator--()实现双向迭代 - 加
operator+=/operator[]实现随机访问 - 写
const_iterator(只读迭代器) - 给
std::sort等算法使用(需要完整随机访问)
总结
手写迭代器其实非常简单:
- 迭代器 = 包装指针 + 标准运算符
- 容器 = 数据 + begin() + end()
- 5 个类型别名 + 4 个运算符 + 2 个容器方法 = 可用迭代器
- 写对就能支持范围for 和STL 习惯用法