1. C++ STL迭代器深度解析
作为一名长期使用C++进行开发的程序员,STL迭代器是我们日常工作中不可或缺的工具。今天我想系统梳理一下迭代器的类型和使用技巧,希望能帮助大家更好地掌握这个强大的特性。
1.1 迭代器概述与分类
迭代器是STL中用于访问容器元素的通用接口,它抽象了不同容器的访问方式,使得算法可以独立于具体容器工作。根据功能强弱,STL迭代器可分为五种类型:
| 迭代器类型 | 功能特性 | 典型应用场景 |
|---|---|---|
| 输出迭代器 | 只写,单次遍历 | ostream输出流,插入迭代器 |
| 输入迭代器 | 只读,单次遍历 | istream输入流 |
| 前向迭代器 | 读写,可多次单向遍历 | forward_list,无序容器 |
| 双向迭代器 | 可向前/向后移动 | list,关联容器 |
| 随机访问迭代器 | 支持所有指针运算(包括随机跳转和下标访问) | array,vector,string,deque |
这五种迭代器形成了严格的层次关系,高级迭代器拥有低级迭代器的所有功能。理解这种分类对编写通用算法非常重要。
1.2 输出迭代器详解
输出迭代器是最基础的迭代器类型,它只支持单向写入操作。在实际项目中,我经常用它来实现数据输出和容器填充。
核心特性:
- 只能通过
*it = value进行写入操作 - 只能使用
++向前移动 - 不支持重复访问同一位置
- 不支持比较操作(无法判断位置关系)
cpp复制#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
int main() {
// 使用ostream_iterator输出到标准输出
ostream_iterator<int> out_iter(cout, " ");
for(int i=1; i<=5; ++i) {
*out_iter = i*10; // 写入并输出
++out_iter; // 必须移动迭代器
}
// 输出:10 20 30 40 50
// 使用back_inserter填充vector
vector<int> vec;
auto back_iter = back_inserter(vec);
*back_iter = 100; // 相当于vec.push_back(100)
++back_iter; // 虽然实际不需要移动,但语法要求
return 0;
}
注意:输出迭代器每次写入后必须移动,否则可能导致未定义行为。这是新手常犯的错误。
1.3 输入迭代器实战
输入迭代器与输出迭代器相对应,用于单向读取数据流。我在处理输入数据或解析文件时经常使用它。
关键特点:
- 只能通过
*it读取数据 - 只能使用
++向前移动 - 不支持重复读取同一位置
- 仅支持
==和!=比较(判断是否到达末尾)
cpp复制#include <iostream>
#include <iterator>
#include <numeric>
using namespace std;
int main() {
cout << "请输入若干整数,以非数字结束:" << endl;
istream_iterator<int> in_iter(cin); // 绑定到标准输入
istream_iterator<int> end_iter; // 默认构造得到结束迭代器
int sum = accumulate(in_iter, end_iter, 0);
cout << "输入数字的总和是:" << sum << endl;
return 0;
}
实用技巧:
- 默认构造的istream_iterator作为结束标志
- 可以与STL算法直接配合使用(如accumulate)
- 适合处理流式数据,但不适合需要反复访问的场景
1.4 前向迭代器应用场景
前向迭代器比输入/输出迭代器更强大,支持多次访问同一位置。我在处理单向链表时最常使用它。
特性总结:
- 支持读写操作
- 可多次访问同一位置
- 只能单向移动(
++) - 支持相等性比较(
==,!=)
cpp复制#include <forward_list>
#include <iostream>
using namespace std;
int main() {
forward_list<string> flist = {"apple", "banana", "cherry"};
// 第一次遍历:打印所有元素
cout << "第一次遍历:";
for(auto it=flist.begin(); it!=flist.end(); ++it) {
cout << *it << " ";
}
// 第二次遍历:修改元素
for(auto it=flist.begin(); it!=flist.end(); ++it) {
*it = "
