【C++11 之rbegin()、rend() 反向迭代器原理介绍及 重点-限制情况】与正向迭代器对比(互换放在下一p)

C++11 引入了许多新特性,其中包括对 STL(Standard Template Library)的改进。在 STL 容器中,rbegin() 和 rend() 是两个新的成员函数,它们分别返回指向容器最后一个元素的反向迭代器(reverse iterator)和指向容器"理论上的前一个元素"的反向迭代器(该迭代器实际上并不指向任何有效元素,而是作为结束标记)。

反向迭代器介绍

反向迭代器是一种特殊的迭代器,它允许我们按照与正向迭代器相反的顺序遍历容器。也就是说,如果我们使用正向迭代器从容器的开始遍历到结束,那么使用反向迭代器就是从容器的结束遍历到开始。

使用场景

反向迭代器在需要逆序遍历容器元素的场景中非常有用。例如,你可能想要从后向前检查一个字符串是否以某个子串结尾,或者你可能想要逆序打印一个向量的所有元素。

与正向迭代器原理对比

正向迭代器和反向迭代器在原理上的主要区别在于它们如何定义"下一个"元素。对于正向迭代器,++it 将迭代器向前移动到下一个元素;而对于反向迭代器,++it 将迭代器向后移动到"上一个"元素。注意,这里的"上一个"和"下一个"是相对于容器的遍历方向而言的。

代码对比

以下是使用正向迭代器和反向迭代器遍历 std::vector 的示例代码:

cpp 复制代码
#include <iostream>  
#include <vector>  
  
int main() {  
    std::vector<int> v = {1, 2, 3, 4, 5};  
  
    // 使用正向迭代器遍历  
    for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {  
        std::cout << *it << ' ';  
    }  
    std::cout << '\n';  
  
    // 使用反向迭代器遍历  
    for (std::vector<int>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit) {  
        std::cout << *rit << ' ';  
    }  
    std::cout << '\n';  
  
    return 0;  
}

在这个示例中,我们首先使用正向迭代器从前往后遍历 vector,然后使用反向迭代器从后往前遍历 vector。输出将是:

bash 复制代码
1 2 3 4 5   
5 4 3 2 1

注意,虽然正向迭代器和反向迭代器在语法上有所不同(特别是它们的类型),但它们的用法非常相似:都可以使用 * 运算符来解引用迭代器以访问元素,都可以使用 ++ 运算符来移动迭代器,等等。

看完你会发现反向迭代器其实也没有太多特殊的。是的,但反向迭代器本身设置了很多的限制,所以认识反向迭代器,我们一定要熟悉其限制机制;

重点-限制情况

  1. 依赖双向迭代器:
    反向迭代器通常基于容器的双向迭代器实现。因此,如果容器仅支持单向迭代器(如某些输入迭代器),则无法使用反向迭代器。
    这意味着反向迭代器不能用于如 std::istream_iterator 这样的单向迭代器类型。
  2. 特定操作不可用:
    反向迭代器不支持随机访问迭代器的某些操作,如 operator+=、operator+、operator-=、operator- 和 operator[]。这是因为反向迭代器的内部机制并不直接支持这些操作。
    例如,你不能直接通过 rit + 3 来跳过三个元素(其中 rit 是一个反向迭代器),因为这需要知道"理论上的前一个元素"的位置,这在反向迭代器的上下文中是不可知的。
  3. 引用和指针的语义:(这个难以理解就在下一p中熟悉-C++17新特性)
    反向迭代器的 &*rit(取反向迭代器 rit 指向元素的地址)操作与正向迭代器有所不同。在反向迭代器的上下文中,&*rit 实际上引用的是迭代器在原有序列中引用的元素之外(右侧)一个位置的元素。
    这意味着你不能直接通过反向迭代器来获取容器中元素的原始地址(除非你使用额外的逻辑来转换它)。
  4. 迭代器的有效性:
    反向迭代器的有效性同样受到容器修改操作的影响。如果在遍历过程中修改了容器的大小(如添加或删除元素),则可能导致反向迭代器失效。
    需要注意的是,即使正向迭代器在容器修改后仍然有效,其对应的反向迭代器也可能不再有效。
  5. 类型差异:
    反向迭代器的类型与正向迭代器的类型不同。在 C++ 中,你需要使用如 std::vector::reverse_iterator 这样的类型来声明反向迭代器。
    这意味着你不能直接将正向迭代器赋值给反向迭代器,或者期望它们在类型上兼容。
  6. 使用场景限制:
    虽然反向迭代器在处理需要逆序遍历容器的场景时非常有用,但它们并不适用于所有情况。在某些情况下,使用正向迭代器可能更加直观和高效。

归纳来说,反向迭代器的限制主要源于其基于双向迭代器的设计和实现方式,以及与正向迭代器的差异。这些限制在使用反向迭代器时需要特别注意,以避免潜在的问题和错误。

相关推荐
奋斗的小花生1 分钟前
c++ 多态性
开发语言·c++
魔道不误砍柴功4 分钟前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
闲晨7 分钟前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程34 分钟前
一个例子来说明Ada语言的实时性支持
开发语言·ada
UestcXiye2 小时前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
Chrikk2 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*2 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue2 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man2 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
霁月风3 小时前
设计模式——适配器模式
c++·适配器模式