实现C++ const迭代器时出现崩溃,且疑惑缺失关键运算符的代码为何可正常编译
嘿,这个问题挺有意思的——其实你没意识到,你这里用的「迭代器」根本不是自定义的迭代器类,而是原生指针,而指针本身就自带你以为缺失的那些运算符!
核心原因:你的「迭代器」是原生指针,自带运算符
先拆解范围for循环的底层逻辑(简化版):
auto __begin = begin(persons); auto __end = end(persons); for (; __begin != __end; ++__begin) { const auto p = *__begin; // 你的循环体逻辑 }
看你的代码,begin和end返回的都是const List<T>*类型——也就是指针。而C++里的原生指针本身就支持:
operator++:把指针在内存中移动到下一个同类型对象的地址(注意:是按内存偏移,不是链表的tail节点)operator!=:直接比较两个指针的内存地址是否不同operator*:解引用指针得到指向的对象
所以编译器根本不需要你额外实现这些运算符,直接用指针的内置操作就够了——这就是代码能编译通过的原因。
但这里有个致命的逻辑错误!
虽然代码能编译,但它完全没有正确遍历你的链表!
你的链表节点是用new分散在堆内存中的,彼此内存地址不连续。每次++__begin的时候,只是把指针在内存里往后跳sizeof(List<Person>)字节,而不是跳到当前节点tail指针指向的下一个链表节点。运行时要么输出乱码,要么直接触发内存访问错误,完全不是你想要的链表遍历效果。
正确的做法:实现真正的链表迭代器
要正确遍历链表,你需要自定义一个迭代器类,在里面重载运算符来贴合链表的结构:
#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){} }; // 自定义链表迭代器 template<class T> class ListIterator { private: const List<T>* current; public: ListIterator(const List<T>* node) : current(node) {} // 重载前置++:移动到下一个链表节点 ListIterator& operator++() { if (current) current = current->tail; return *this; } // 重载!=:判断是否到达末尾 bool operator!=(const ListIterator& other) const { return current != other.current; } // 重载*:返回当前节点的元素指针 const T* operator*() const { return current->head; } }; // 修改begin和end,返回自定义迭代器 template<class T> ListIterator<T> begin(const List<T>& l) { return ListIterator<T>(&l); } template<class T> ListIterator<T> end(const List<T>&) { return ListIterator<T>(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))); // 注意这里要解引用指针,传入List对象的引用 for (const auto p: *persons) { std::cout << (*p)->age << "\n"; } return 0; }
这个版本的代码会正确沿着tail指针遍历每个链表节点,输出预期的16、27、38。
内容的提问来源于stack exchange,提问作者OrenIshShalom
相关产品推荐
相关产品推荐

