将std容器的正向迭代器转换成反向迭代器

迭代器是一种很有用的设计模式,它提供一种方法顺序访问一个聚合对象(如列表、集合、树等)中的各个元素,而又不暴露该对象的内部表示。迭代器最大的好处是实现了遍历逻辑与数据结构解耦,比如说,你使用迭代器实现了某个容器对象的遍历,后来发现这个容器不合适,需要更换成另外一个容器,那么在修改容器类型之后,就不用修改遍历操作。

虽然现代编程都内置了对迭代器模式的支持,但是自己在封装某个数据对象实现的时候,就免不了自己实现迭代器。一般而言是先封装正向迭代器,如果还有反向遍历的需求,那么就可以通过正向迭代器来实现反向迭代器。C++中std的迭代器实现还是挺绕的,比如正向迭代器begin是第一个元素,end最后一个元素的后一个元素;反向迭代器rbegin是最后一个元素,rend是第一个元素的前一个元素------两者最好不要混用,用正向迭代器实现反向遍历操作多半不靠谱。

那么具体如何通过正向迭代器来获取反向迭代器呢?可以使用如下公式:

反向迭代器 r_it = std::reverse_iterator<正向迭代器类型>(fwd_it + 1);

可参考如下示例来验证:

cpp 复制代码
#include <iostream>
#include <vector>

using namespace std;

int main() {
  // 创建一个 vector 用于测试
  std::vector<int> vec = {10, 20, 30, 40, 50};
  std::cout << "容器内容: ";
  for (const auto& elem : vec) {
    std::cout << elem << " ";
  }
  std::cout << std::endl << std::endl;

  // --- 测试 1: fwd_it 指向第一个元素 (10) ---
  std::cout << "=== 测试 1: fwd_it 指向第一个元素 ===" << std::endl;
  auto fwd_it_first = vec.begin();  // 指向 10
  std::cout << "fwd_it_first 指向的元素: " << *fwd_it_first << std::endl;

  // 使用公式构造反向迭代器
  auto r_it_first =
      std::reverse_iterator<std::vector<int>::iterator>(fwd_it_first + 1);
  std::cout << "r_it_first 指向的元素: " << *r_it_first << std::endl;
  // 验证它们是否指向同一个值
  std::cout << "指向同一个元素吗? "
            << (*fwd_it_first == *r_it_first ? "是" : "否") << std::endl;
  std::cout << std::endl;

  // --- 测试 2: fwd_it 指向最后一个元素 (50) ---
  std::cout << "=== 测试 2: fwd_it 指向最后一个元素 ===" << std::endl;
  auto fwd_it_last = vec.end() - 1;  // 指向 50 (不能用 vec.end() + 1!)
  std::cout << "fwd_it_last 指向的元素: " << *fwd_it_last << std::endl;

  // 使用公式构造反向迭代器
  auto r_it_last =
      std::reverse_iterator<std::vector<int>::iterator>(fwd_it_last + 1);
  std::cout << "r_it_last 指向的元素: " << *r_it_last << std::endl;
  // 验证它们是否指向同一个值
  std::cout << "指向同一个元素吗? "
            << (*fwd_it_last == *r_it_last ? "是" : "否") << std::endl;
  std::cout << std::endl;

  // --- 测试 3: fwd_it 指向中间元素 (30) ---
  std::cout << "=== 测试 3: fwd_it 指向中间元素 ===" << std::endl;
  auto fwd_it_middle = vec.begin() + 2;  // 指向 30
  std::cout << "fwd_it_middle 指向的元素: " << *fwd_it_middle << std::endl;

  // 使用公式构造反向迭代器
  auto r_it_middle =
      std::reverse_iterator<std::vector<int>::iterator>(fwd_it_middle + 1);
  std::cout << "r_it_middle 指向的元素: " << *r_it_middle << std::endl;
  // 验证它们是否指向同一个值
  std::cout << "指向同一个元素吗? "
            << (*fwd_it_middle == *r_it_middle ? "是" : "否") << std::endl;
  std::cout << std::endl;
}

运行的结果是:

shell 复制代码
容器内容: 10 20 30 40 50

=== 测试 1: fwd_it 指向第一个元素 ===
fwd_it_first 指向的元素: 10
r_it_first 指向的元素: 10
指向同一个元素吗? 是

=== 测试 2: fwd_it 指向最后一个元素 ===
fwd_it_last 指向的元素: 50
r_it_last 指向的元素: 50
指向同一个元素吗? 是

=== 测试 3: fwd_it 指向中间元素 ===
fwd_it_middle 指向的元素: 30
r_it_middle 指向的元素: 30
指向同一个元素吗? 是

说明公式是成立的。不过在使用这个公式之前需要检查fwd_it是不是end,因为end是容器最后一个元素的后一个元素,对其进行加1操作可能会导致未定义的行为而出错。

相关推荐
钓鱼的肝3 小时前
梳理(1-5)
c++·经验分享·笔记·算法·青少年编程
jimy14 小时前
readelf 查看“派生类”的vtable符号
开发语言·c++
蒸蒸yyyyzwd4 小时前
cpp 选手秋招学习笔记 day37 面经学习
c++·八股
YYYing.4 小时前
【C++进阶系列 (七)】C++ RTTI 深度剖析:从 typeid 到 dynamic_cast 的底层之旅
开发语言·c++·c/c++·rtti
钓鱼的肝6 小时前
csp-j-s总结(2)
c++·经验分享·笔记·算法·青少年编程
重生的黑客6 小时前
Qt 常用控件精讲(1):QWidget 核心属性全解 —— 从 geometry 到 qrc 与 QSS
c++·qt·qwidget·qss·常用控件
Hespethorn6 小时前
取 `X-Forwarded-For` 首段做频控 key,等于把限流开关交给了调用方
c++
米糕闯编程6 小时前
鱼香ros2(七)功能包组织C++节点
c++·ros2·cmakelists
汉克老师7 小时前
GESP2026年9月认证C++四级( 第三部分编程题(1、新汉诺塔))精讲
c++·gesp·小学生·学c++编程
唠玖馆8 小时前
智能指针详解
c++