C++迭代器(iterator)

-- TOC --

迭代器iterator是C++ STL的组件之一,作用是用来遍历容器container,而且是通用的遍历容器元素的方式,无论容器是基于什么数据结构实现。尽管不同的数据结构,遍历元素的方式不一样,但是用迭代器遍历不同容器的代码可以是完全一样的。

C++提供的range-based loop,就是基于迭代器的实现。

简单来说,迭代器就是重载了++--*等操作符的对象,迭代器一般作为容器类型的子类存在。由于STL中的容器都实现了接口风格完全一致的迭代器,因此,通过迭代器遍历容器中对象的代码,也几乎是一样的。

The interface between containers and algorithms is the iterator. An iterator is a type that knows the internal structure of a container and exposes simple, pointer­like operations to a container’s elements.

常用的迭代器按功能强弱分为输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器 5 种。

假设 p 是一个前向迭代器,则 p 支持 ++p,p++,*p 操作,还可以被复制或赋值,可以用 == 和 != 运算符进行比较。此外,两个正向迭代器可以互相赋值。

双向迭代器具有前向迭代器的全部功能,除此之外,假设 p 是一个双向迭代器,则还可以进行 --p 或者 p-- 操作。

随机访问迭代器具有双向迭代器的全部功能。除此之外,假设 p 是一个随机访问迭代器,i 是一个整型变量或常量,则 p 还支持以下操作:

p += i:使得 p 往后移动 i 个元素。
p -= i:使得 p 往前移动 i 个元素。
p + i:返回 p 后面第 i 个元素的迭代器。
p - i:返回 p 前面第 i 个元素的迭代器。
p[i]:返回 p 后面第 i 个元素的引用。

此外,两个随机访问迭代器 p1、p2 还可以用 <、>、<=、>= 运算符进行比较。另外,表达式 p2-p1 也是有定义的,其返回值表示 p2 所指向元素和 p1 所指向元素的序号之差(也可以说是 p2 和 p1 之间的元素个数减一)。

另外,cbegin中的c,表示const,通过const迭代器,不可以修改对象的内容。

迭代器的实现,不一定是通过指针,C++迭代器更像一个规范。

下面,我来尝试实现自己的第1个学习用迭代器。这段代码实现了依附于fib对象的正向迭代器:

#include <iostream>
using namespace std;


struct fib {

    struct fib_iterator {
        fib_iterator(void) = default;

        bool operator!=(int x) const {
            return x >= cur;
        }

        fib_iterator& operator++() {
            const int tmp = cur;
            cur += last;
            last = tmp;
            return *this;
        }

        int operator*() {
            return cur;
        }

    private:
        int cur{1};
        int last{1};
    };

    explicit fib(int max): max{max} {}

    fib_iterator begin() const {
        return fib_iterator{};
    }

    int end() const {
        return max;
    }

private:
    int max;
};


int main(void) {
    auto f = fib{2000};

    // basic for loop
    for (auto x{f.begin()}; x!=f.end(); ++x)
        cout << *x << " "; // x is iterator
    cout << endl;

    // range-based for loop
    for (auto x: f)
        cout << x << " ";  // x is int object
    cout << endl;
    return 0;
}

编译和输出:

$ g++ -Wall -Wextra test.cpp -o test
$ ./test
1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 
1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 

fib对象的end接口返回max,它的迭代器重载了!=符号,在循环时与max进行比较,如果达到max了,就返回false,此时循环的判断条件不再满足,循环结束。

因为*操作符在重载时,返回的是int值,而不是int引用,因此在使用range-based loop的时候,就不能写成auto &x

本文链接:https://cs.pynote.net/sf/c/cpp/202211042/

-- EOF --

-- MORE --