实现 cpp const 迭代器崩溃和燃烧
implementing a cpp const iterator crashes and burns
很多关于 const 迭代器的帖子 (example),但是 none 在循环的上下文中,例如:
for (const auto it: container) { ... }
当我开始实施时,编译器抱怨缺少begin
和end
鼓励 ,希望这样的抱怨可以引导我补齐缺失的部分。我错了。下面的代码编译得很好,尽管它肯定缺少 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*
。这意味着 begin
和 end
函数不是在指针上定义的,而是在 List 对象本身上定义的,我们迭代 *persons
而不是 persons
.
- 在
for (const auto p : *persons)
中,p
是一个Person
,不是指针。
#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;
}
很多关于 const 迭代器的帖子 (example),但是 none 在循环的上下文中,例如:
for (const auto it: container) { ... }
当我开始实施时,编译器抱怨缺少begin
和end
鼓励 ,希望这样的抱怨可以引导我补齐缺失的部分。我错了。下面的代码编译得很好,尽管它肯定缺少 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*
。这意味着begin
和end
函数不是在指针上定义的,而是在 List 对象本身上定义的,我们迭代*persons
而不是persons
.- 在
for (const auto p : *persons)
中,p
是一个Person
,不是指针。
#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;
}