实现 cpp const 迭代器崩溃和燃烧

implementing a cpp const iterator crashes and burns

很多关于 const 迭代器的帖子 (example),但是 none 在循环的上下文中,例如:

for (const auto it: container) { ... }

当我开始实施时,编译器抱怨缺少beginend鼓励 ,希望这样的抱怨可以引导我补齐缺失的部分。我错了。下面的代码编译得很好,尽管它肯定缺少 operator++operator!= 的等价物:

#include <iostream>
template<class T> class List { public:
    const T *head;
    const List<T> *tail;
    List(const T *h, const List<T> *t):head(h),tail(t){}
    const T *operator*() const { return head; } };

template<class T> const List<T> *begin(const List<T> *l) { return l; }
template<class T> const List<T> *end  (const List<T> *l) { return nullptr; }

class Person { public: int age; Person(int a):age(a){} };
typedef List<Person> Persons;

int main(int argc, char **argv) {
    Person *p1 = new Person(16);
    Person *p2 = new Person(27);
    Person *p3 = new Person(38);

    Persons *persons = new Persons(p1,
        new Persons(p2,
        new Persons(p3, nullptr)));

    for (const auto p: persons) { std::cout << (*p)->age << "\n"; }
    return 0; }

这段代码如何编译?

您还没有定义 ++!=,但是对于您的迭代器类型 const List<T>*,它们是完美定义的,因为它是一个指针类型。但是,++ 的默认行为不会执行您想要的操作,即跟随 tail 指针。

为了让您的迭代器具备关于如何实现 ++ 的特殊知识,您可能希望使用单独的自定义迭代器 class,而不是使用指针。

我还对您的代码进行了一些其他更改:

  • List 类型是可迭代的,而不是 List*。这意味着 beginend 函数不是在指针上定义的,而是在 List 对象本身上定义的,我们迭代 *persons 而不是 persons.
  • for (const auto p : *persons)中,p是一个Person,不是指针。

godbolt.org link

#include <iostream>
template<class T> class List { public:
    const T *head;
    const List<T> *tail;
    List(const T *h, const List<T> *t):head(h),tail(t){}
    const T *operator*() const { return head; }

    class const_iterator {
        const List<T>* cur = nullptr;
    public:
        explicit const_iterator(const List<T>* list) : cur(list) {}
        const_iterator& operator++() {
            cur = cur->tail;
            return *this;
        }
        bool operator!=(const const_iterator& other) const {
            return cur != other.cur;
        }
        const T& operator*() const {
            return *cur->head;
        }
    };

    const_iterator begin() const {
        return const_iterator(this);
    }

    const_iterator end() const {
        return const_iterator(nullptr);
    }
};

class Person { public: int age; Person(int a):age(a){} };
typedef List<Person> Persons;

int main(int argc, char **argv) {
    Person *p1 = new Person(16);
    Person *p2 = new Person(27);
    Person *p3 = new Person(38);

    Persons *persons = new Persons(p1,
        new Persons(p2,
        new Persons(p3, nullptr)));

    for (const auto p: *persons) {
        std::cout << p.age << "\n";
    }
    return 0;
}