C++ 标准库 iterator

下面对 C++ 标准库中 <iterator> 头文件所提供的工具和类型做一个系统、详细的梳理与讲解,内容包含迭代器分类、迭代器_traits、常用迭代器操作、迭代器适配器、流迭代器等,并配以使用示例和复杂度说明。


一、概述

  • <iterator> 提供了对迭代器进行分类标记、特性萃取(traits)、基础操作函数和若干通用适配器。
  • 迭代器(Iterator)是 STL 容器和算法间的桥梁,分为输入输出前向双向随机访问(以及 C++17 起的连续)等类别。
  • 通过迭代器适配器,可将普通指针或其他类型“包装”成符合特定接口的迭代器,如插入迭代器、反向迭代器、移动迭代器等。

二、迭代器类别(Iterator Categories)

类别特性示例类型
输入迭代器只读,对应单次遍历;支持 *it++itstd::istream_iterator<T>
输出迭代器只写,只能递增一次;支持 *it = v++itstd::ostream_iterator<T>
前向迭代器可多次遍历;兼具输入/输出迭代器功能;支持比较 ==!=std::forward_list<T>::iterator
双向迭代器在前向迭代器基础上支持 --itstd::list<T>::iterator
随机访问迭代器在双向迭代器基础上支持跳跃访问:it + nit[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 获得原有内容

八、实践建议

  1. 选择合适的迭代器类别
    • 仅需单次扫描输入流时,用输入迭代器;需在容器中任意位置高速访问时,用随机访问迭代器(如 vector、原生指针)。
  2. 优先使用标准操作函数
    • std::advance/std::distance 可屏蔽类别差异;std::begin/std::end 支持原生数组和自定义容器。
  3. 善用插入迭代器
    • 可将算法输出直接写入容器,无需手动管理下标或 push_back
  4. 注意流迭代器的开销
    • 适合一次性、批量读写;但对格式和性能要求高时,手动循环更可控。

通过对 <iterator> 中迭代器类别、traits、操作函数与适配器的全面梳理,能帮助你在日常开发与算法编写时快速选型并写出高效、可读性强的代码。祝学习愉快!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注