当前位置: 首页 > news >正文

C++底层刨析章节二:迭代器原理与实现:STL的万能胶水

前言

在STL的设计中,迭代器扮演着"万能胶水"的角色,它优雅地连接了容器和算法。正如Bjarne Stroustrup所说:"C++的STL之所以强大,很大程度上得益于迭代器抽象。"本文将深入探讨迭代器的分类、实现原理以及如何自定义迭代器,让你彻底理解这一核心组件。

一、迭代器分类及其特性

迭代器不是单一类型,而是根据功能分为五大类别,每一类都有特定的能力和限制。

迭代器类别层次结构

#include <iterator>// 迭代器五大类别
struct input_iterator_tag {};        // 输入迭代器
struct output_iterator_tag {};       // 输出迭代器
struct forward_iterator_tag {};      // 前向迭代器
struct bidirectional_iterator_tag {};// 双向迭代器
struct random_access_iterator_tag {};// 随机访问迭代器

各类迭代器的特性

1. 输入迭代器(Input Iterator)
  • 能力:只能读取,只能前向移动,只能单遍扫描
  • 典型应用istream_iterator
  • 支持操作++, *, ->, ==, !=
#include <iostream>
#include <iterator>void demo_input_iterator() {std::istream_iterator<int> input(std::cin);std::istream_iterator<int> end;while (input != end) {std::cout << "Read: " << *input << std::endl;++input;}
}
2. 输出迭代器(Output Iterator)
  • 能力:只能写入,只能前向移动,只能单遍扫描
  • 典型应用ostream_iterator
  • 支持操作++, * (仅用于赋值)
#include <iostream>
#include <iterator>
#include <vector>void demo_output_iterator() {std::vector<int> vec = {1, 2, 3, 4, 5};std::ostream_iterator<int> output(std::cout, " ");for (int val : vec) {*output = val;  // 写入输出流++output;}
}
3. 前向迭代器(Forward Iterator)
  • 能力:可读写,可前向移动,可多遍扫描
  • 典型应用forward_list的迭代器
  • 支持操作:包含输入输出迭代器的所有操作
4. 双向迭代器(Bidirectional Iterator)
  • 能力:在前向迭代器基础上增加反向移动能力
  • 典型应用list, set, map的迭代器
  • 支持操作:增加 -- 操作
#include <list>void demo_bidirectional_iterator() {std::list<int> lst = {1, 2, 3, 4, 5};auto it = lst.end();// 反向遍历while (it != lst.begin()) {--it;std::cout << *it << " ";}
}
5. 随机访问迭代器(Random Access Iterator)
  • 能力:在双向迭代器基础上支持随机访问
  • 典型应用vector, deque, 原始指针
  • 支持操作:增加 +, -, [], <, > 等操作
#include <vector>void demo_random_access_iterator() {std::vector<int> vec = {1, 2, 3, 4, 5};auto it = vec.begin();// 随机访问std::cout << "Third element: " << it[2] << std::endl;std::cout << "Distance: " << (vec.end() - vec.begin()) << std::endl;
}

迭代器类别关系图

随机访问迭代器 → 双向迭代器 → 前向迭代器 → 输入迭代器→ 输出迭代器

二、迭代器萃取器(Traits)技术

迭代器萃取是STL中最重要的元编程技术之一,它允许算法在编译时获取迭代器的特性信息。

为什么需要迭代器萃取?

考虑这样一个问题:如何实现一个distance函数计算两个迭代器之间的距离?

template<typename Iterator>
typename std::iterator_traits<Iterator>::difference_type
distance(Iterator first, Iterator last) {// 我们需要知道迭代器类别来选择最优算法
}

迭代器萃取器的实现

// 基本的迭代器特质模板
template<typename Iterator>
struct iterator_traits {using iterator_category = typename Iterator::iterator_category;using value_type        = typename Iterator::value_type;using difference_type   = typename Iterator::difference_type;using pointer           = typename Iterator::pointer;using reference         = typename Iterator::reference;
};// 针对原始指针的特化版本
template<typename T>
struct iterator_traits<T*> {using iterator_category = std::random_access_iterator_tag;using value_type        = T;using difference_type   = std::ptrdiff_t;using pointer           = T*;using reference         = T&;
};// 针对const指针的特化版本
template<typename T>
struct iterator_traits<const T*> {using iterator_category = std::random_access_iterator_tag;using value_type        = T;using difference_type   = std::ptrdiff_t;using pointer           = const T*;using reference         = const T&;
};

使用萃取器实现通用算法

// 根据迭代器类别选择不同的实现
template<typename InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance_impl(InputIterator first, InputIterator last, std::input_iterator_tag) {// 线性复杂度实现,用于输入迭代器typename iterator_traits<InputIterator>::difference_type n = 0;while (first != last) {++first;++n;}return n;
}template<typename RandomAccessIterator>
typename iterator_traits<RandomAccessIterator>::difference_type
distance_impl(RandomAccessIterator first, RandomAccessIterator last,std::random_access_iterator_tag) {// 常数复杂度实现,用于随机访问迭代器return last - first;
}// 统一的distance接口
template<typename Iterator>
typename iterator_traits<Iterator>::difference_type
distance(Iterator first, Iterator last) {return distance_impl(first, last,typename iterator_traits<Iterator>::iterator_category());
}

三、自定义迭代器实现

让我们实现一个简单的自定义迭代器,用于遍历一个固定数组。

基本迭代器实现

template<typename T>
class ArrayIterator {
public:// 必需的迭代器类型定义using iterator_category = std::random_access_iterator_tag;using value_type        = T;using difference_type   = std::ptrdiff_t;using pointer           = T*;using reference         = T&;// 构造函数explicit ArrayIterator(T* ptr = nullptr) : ptr_(ptr) {}// 解引用操作reference operator*() const { return *ptr_; }pointer operator->() const { return ptr_; }// 前缀递增ArrayIterator& operator++() {++ptr_;return *this;}// 后缀递增ArrayIterator operator++(int) {ArrayIterator temp = *this;++ptr_;return temp;}// 前缀递减ArrayIterator& operator--() {--ptr_;return *this;}// 后缀递减ArrayIterator operator--(int) {ArrayIterator temp = *this;--ptr_;return temp;}// 随机访问操作ArrayIterator operator+(difference_type n) const {return ArrayIterator(ptr_ + n);}ArrayIterator operator-(difference_type n) const {return ArrayIterator(ptr_ - n);}difference_type operator-(const ArrayIterator& other) const {return ptr_ - other.ptr_;}reference operator[](difference_type n) const {return ptr_[n];}// 比较操作bool operator==(const ArrayIterator& other) const {return ptr_ == other.ptr_;}bool operator!=(const ArrayIterator& other) const {return ptr_ != other.ptr_;}bool operator<(const ArrayIterator& other) const {return ptr_ < other.ptr_;}bool operator>(const ArrayIterator& other) const {return ptr_ > other.ptr_;}private:T* ptr_;
};

使用自定义迭代器

#include <algorithm>
#include <iostream>void demo_custom_iterator() {int arr[] = {5, 2, 8, 1, 9};const int size = sizeof(arr) / sizeof(arr[0]);ArrayIterator<int> begin(arr);ArrayIterator<int> end(arr + size);// 使用STL算法std::sort(begin, end);// 使用范围for循环(需要提供begin/end函数)for (auto it = begin; it != end; ++it) {std::cout << *it << " ";}std::cout << std::endl;
}

为自定义容器实现迭代器

template<typename T>
class SimpleVector {
public:// 内部迭代器定义class Iterator {public:using iterator_category = std::random_access_iterator_tag;using value_type        = T;using difference_type   = std::ptrdiff_t;using pointer           = T*;using reference         = T&;explicit Iterator(T* ptr = nullptr) : ptr_(ptr) {}// 实现必要的迭代器操作...private:T* ptr_;};// 容器接口Iterator begin() { return Iterator(data_); }Iterator end() { return Iterator(data_ + size_); }private:T* data_;size_t size_;size_t capacity_;
};

四、迭代器适配器

STL提供了多种迭代器适配器,可以改变迭代器的行为:

1. 反向迭代器(Reverse Iterator)

#include <vector>
#include <iterator>void demo_reverse_iterator() {std::vector<int> vec = {1, 2, 3, 4, 5};for (auto it = vec.rbegin(); it != vec.rend(); ++it) {std::cout << *it << " ";  // 输出: 5 4 3 2 1}
}

2. 插入迭代器(Insert Iterator)

#include <vector>
#include <iterator>
#include <algorithm>void demo_insert_iterator() {std::vector<int> source = {1, 2, 3, 4, 5};std::vector<int> target;std::copy(source.begin(), source.end(), std::back_inserter(target));
}

总结

迭代器是STL设计的核心智慧所在,它通过统一的接口抽象了不同容器的访问方式,使得算法和容器能够独立发展。理解迭代器的分类、萃取技术以及实现原理,对于深入掌握STL和编写高效的泛型代码至关重要。

关键要点:

  1. 迭代器分为五大类别,每种类别有不同的能力和限制
  2. 迭代器萃取技术使得算法能够根据迭代器特性选择最优实现
  3. 自定义迭代器需要提供必要的类型定义和操作符重载
  4. 迭代器适配器可以改变现有迭代器的行为

思考题

  1. 为什么输入迭代器和输出迭代器只能单遍扫描?
  2. 迭代器萃取技术如何帮助实现advance函数?
  3. 如何为树形结构(如二叉搜索树)实现迭代器?

在下一篇文章中,我们将探讨函数对象与适配器的实现原理,揭开STL中另一种强大的抽象机制。


文章转载自:

http://6jyduMAe.cxtbh.cn
http://YHZOJWaa.cxtbh.cn
http://EuytvvQJ.cxtbh.cn
http://HWE6ugnk.cxtbh.cn
http://oZ7cop6n.cxtbh.cn
http://qTK45xkh.cxtbh.cn
http://GWjuvH0c.cxtbh.cn
http://HTyDiTu1.cxtbh.cn
http://evt7mg6j.cxtbh.cn
http://6lQa6syw.cxtbh.cn
http://h8AnETWl.cxtbh.cn
http://QCeeSdJv.cxtbh.cn
http://Wm5tFfNn.cxtbh.cn
http://iMFt41jE.cxtbh.cn
http://bieNUZmu.cxtbh.cn
http://AAVXfEHe.cxtbh.cn
http://oRPjetAJ.cxtbh.cn
http://jsH6GmQX.cxtbh.cn
http://Lb7IMFeR.cxtbh.cn
http://NiRF8trC.cxtbh.cn
http://YL2L9fJe.cxtbh.cn
http://HFP5d0ub.cxtbh.cn
http://g9v9MqGs.cxtbh.cn
http://qxWcSuVi.cxtbh.cn
http://HeXzVNJb.cxtbh.cn
http://sOoJnQKw.cxtbh.cn
http://Ql9SZWic.cxtbh.cn
http://veUILYl1.cxtbh.cn
http://K5ZXnWhV.cxtbh.cn
http://mvAvsNZ1.cxtbh.cn
http://www.dtcms.com/a/388434.html

相关文章:

  • 学习Python中Selenium模块的基本用法(14:页面打印)
  • 便携式管道推杆器:通信与电力基础设施升级中的“隐形推手”
  • leetcode 349 两个数组的交集
  • UV映射!加入纹理!
  • 车辆DoIP声明报文/识别响应报文的UDP端口规范
  • Elasticsearch 2.x版本升级指南
  • OpenCV 人脸检测、微笑检测 原理及案例解析
  • [Python编程] Python3 集合
  • [性能分析与优化]伪共享问题(perf + cpp)
  • OC-动画实现折叠cell
  • 关于层级问题
  • Linux基础命令汇总
  • getchar 和 putchar
  • 【序列晋升】35 Spring Data Envers 轻量级集成数据审计
  • 快速入门HarmonyOS应用开发(二)
  • 绿联、极空间、飞牛NAS无需安装,实现快速远程访问
  • Datawhale 理工科-大模型入门实训课程 202509 第1次作业
  • 城市治理综合管理平台
  • 《嵌入式硬件(十三):基于IMX6ULL的增强型中断周期定时器(EPIT)操作》
  • PM2 入门指南与常用命令(含 开机自启、Node.js 及 Java 服务部署)
  • 汽车多核架构中内存系统故障检测的改进算法
  • C++真的比Python更快吗?
  • 【实操分享】使用 SeeDream 4.0 进行 AI 修图——开启专属“AI 云旅拍”
  • 不依赖第三方,不销毁重建,loveqq 框架如何原生实现动态线程池?
  • Python中正则的三个基础方法
  • 最外层的项目没有父pom配置文件,有很多子模块(maven项目)导入idea中,左侧模块显示不全问题解决
  • 前端将一个 DOM 元素滚动到视口顶部
  • 前端-防重复点击/防抖的方案
  • doris数据库问题
  • PyQt5中实现只读QLineEdit控件的完整指南