C++ 标准库 iterator
下面对 C++ 标准库中 <iterator>
头文件所提供的工具和类型做一个系统、详细的梳理与讲解,内容包含迭代器分类、迭代器_traits、常用迭代器操作、迭代器适配器、流迭代器等,并配以使用示例和复杂度说明。
一、概述
<iterator>
提供了对迭代器进行分类标记、特性萃取(traits)、基础操作函数和若干通用适配器。- 迭代器(Iterator)是 STL 容器和算法间的桥梁,分为输入、输出、前向、双向、随机访问(以及 C++17 起的连续)等类别。
- 通过迭代器适配器,可将普通指针或其他类型“包装”成符合特定接口的迭代器,如插入迭代器、反向迭代器、移动迭代器等。
二、迭代器类别(Iterator Categories)
类别 | 特性 | 示例类型 |
---|---|---|
输入迭代器 | 只读,对应单次遍历;支持 *it , ++it | std::istream_iterator<T> |
输出迭代器 | 只写,只能递增一次;支持 *it = v , ++it | std::ostream_iterator<T> |
前向迭代器 | 可多次遍历;兼具输入/输出迭代器功能;支持比较 == , != | std::forward_list<T>::iterator |
双向迭代器 | 在前向迭代器基础上支持 --it | std::list<T>::iterator |
随机访问迭代器 | 在双向迭代器基础上支持跳跃访问:it + n , it[n] , 比较 < | std::vector<T>::iterator |
连续迭代器(C++17) | 随机访问迭代器 + 保证元素在内存中连续 | 原生指针 T* |
三、std::iterator_traits
- 目的:统一取得任意迭代器的五大成员类型
template<typename Iterator> struct iterator_traits { using difference_type = typename Iterator::difference_type; using value_type = typename Iterator::value_type; using pointer = typename Iterator::pointer; using reference = typename Iterator::reference; using iterator_category = typename Iterator::iterator_category; };
- 对原生指针也有特化:
template<typename T> struct iterator_traits<T*> { using difference_type = ptrdiff_t; using value_type = T; using pointer = T*; using reference = T&; using iterator_category = std::random_access_iterator_tag; };
四、常用迭代器操作函数
这些函数都定义在 <iterator>
中,适用于任意符合相应类别的迭代器。
函数 | 功能 | 复杂度 |
---|---|---|
std::advance(it, n) | 将迭代器前进(或后退)n 步 | 输入/前向/双向:O(n);随机访问:O(1) |
std::distance(a, b) | 计算两个迭代器之间的距离 | 同上 |
std::next(it, n) | 返回前进 n 步后的新迭代器(不修改原迭代器) | 同上 |
std::prev(it, n) | 返回后退 n 步后的新迭代器(不修改原迭代器) | 同上 |
std::begin(c) / std::end(c) | 获取容器或原生数组的开始/结束迭代器 | O(1) |
std::cbegin(c) / std::cend(c) | 返回 const 迭代器 | O(1) |
示例:使用 advance
与 distance
#include <iterator>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v{10,20,30,40,50};
auto it = std::begin(v);
// 跳过两步
std::advance(it, 2);
std::cout << *it << "\n"; // 输出 30
// 计算 it 到 end 的距离
auto dist = std::distance(it, std::end(v));
std::cout << dist << "\n"; // 输出 3
}
五、迭代器适配器(Iterator Adapters)
1. 反向迭代器 std::reverse_iterator
- 将任意双向或随机访问迭代器反转方向。
- 常用与反向遍历容器:
for (auto it = v.rbegin(); it != v.rend(); ++it) { // *it 从尾到头访问 }
std::make_reverse_iterator(it)
(C++14 起)可方便创建。
2. 插入迭代器(Insertion Iterators)
std::back_inserter(c)
→back_insert_iterator
,调用c.push_back(x)
std::front_inserter(c)
→front_insert_iterator
,调用c.push_front(x)
std::inserter(c, it)
→insert_iterator
,调用c.insert(it, x)
可与算法配合,避免手动 push_back
/insert
:
#include <algorithm>
#include <iterator>
#include <vector>
#include <list>
int main() {
std::vector<int> src{1,2,3};
std::list<int> dst;
// 将 src 的元素复制到 dst 末尾
std::copy(src.begin(), src.end(), std::back_inserter(dst));
}
六、流迭代器(Stream Iterators)
类型 | 功能 |
---|---|
std::istream_iterator<T> | 从 std::istream 读取 T ,遇流尾构造为 end 迭代器 |
std::istreambuf_iterator<char> | 不跳过空白,逐字符读取 |
std::ostream_iterator<T> | 向 std::ostream 输出 T ,可指定分隔符 |
std::ostreambuf_iterator<char> | 逐字符写出 |
#include <iterator>
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
// 从 cin 读入整数,直到 EOF
std::vector<int> v{ std::istream_iterator<int>(std::cin),
std::istream_iterator<int>() };
// 将 v 输出到 cout,每个元素后跟空格
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, " "));
}
七、移动迭代器(Move Iterator)
std::move_iterator<It>
令解引用得到右值引用,配合算法可避免不必要的拷贝:std::vector<std::string> src = /*…*/; std::vector<std::string> dst; std::copy(std::make_move_iterator(src.begin()), std::make_move_iterator(src.end()), std::back_inserter(dst)); // src 的元素已被“移出”,dst 获得原有内容
八、实践建议
- 选择合适的迭代器类别
- 仅需单次扫描输入流时,用输入迭代器;需在容器中任意位置高速访问时,用随机访问迭代器(如
vector
、原生指针)。
- 仅需单次扫描输入流时,用输入迭代器;需在容器中任意位置高速访问时,用随机访问迭代器(如
- 优先使用标准操作函数
std::advance
/std::distance
可屏蔽类别差异;std::begin
/std::end
支持原生数组和自定义容器。
- 善用插入迭代器
- 可将算法输出直接写入容器,无需手动管理下标或
push_back
。
- 可将算法输出直接写入容器,无需手动管理下标或
- 注意流迭代器的开销
- 适合一次性、批量读写;但对格式和性能要求高时,手动循环更可控。
通过对 <iterator>
中迭代器类别、traits、操作函数与适配器的全面梳理,能帮助你在日常开发与算法编写时快速选型并写出高效、可读性强的代码。祝学习愉快!