带自定义迭代器的双向链表类型转换错误排查求助
双向链表自定义迭代器类型转换错误修复方案
作为编程练习,尝试实现带有自定义迭代器的双向链表,测试时出现大量类型转换错误,代码及编译错误如下:
原实现代码
template<typename Type> class UnorderedList { private: int listsize; struct Node { Type data; Node * next; Node * previous; Node() { next = previous = nullptr; data = Type(); } }; Node * first; Node * last; Node * end_place; // empty node for end() function, not to be used or dereferenced public: // iterators class iterator { private: // internal iterator pointer Node * n_ptr; public: // iterator tags for compiler using iterator_category = std::bidirectional_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = Node; using pointer = Node *; using reference = Node &; // iterator constructor iterator(Node * node) { n_ptr = node; } // iterator operator overloads for bidirectional_iterator reference operator * () { return n_ptr; } pointer operator -> () { return n_ptr; } iterator & operator ++ () { n_ptr = n_ptr -> next; return * this; } iterator operator ++ (int) { iterator temp = * this; ++(* this); return temp; } iterator & operator -- () { n_ptr = n_ptr -> previous; return * this; } iterator operator -- (int) { iterator temp = * this; --(* this); return temp; } friend bool operator == (const iterator & a, const iterator & b) { return (a.n_ptr == b.n_ptr); } friend bool operator != (const iterator & a, const iterator & b) { return (a.n_ptr != b.n_ptr); } }; // begin() and end() returning iterators iterator begin() { return iterator(first); } iterator end() { return iterator(end_place); } // list constructors UnorderedList(int size) { Node * one = nullptr; Node * two = nullptr; two = new Node; two -> previous = one; first = two; for (int i = 1; i < size; ++i) { two = new Node; one -> next = two; two -> previous = one; } last = two; end_place = new Node; end_place -> data = NULL; end_place -> previous = end_place -> next = nullptr; last -> next = end_place; listsize = size; } UnorderedList(int size, Type fill) { Node * one = nullptr; Node * two = nullptr; two = new Node; two -> previous = one; two -> data = fill; first = two; one = two; for (int i = 1; i < size; ++i) { two = new Node; two -> data = fill; one -> next = two; two -> previous = one; } last = two; end_place = new Node; end_place -> data = Type(); end_place -> previous = end_place -> next = nullptr; last -> next = end_place; listsize = size; } UnorderedList(int size, Type * values) { Node * one = nullptr; Node * two = nullptr; two = new Node; two -> previous = one; two -> data = * values; first = two; for (int i = 1; i < size; ++i) { two = new Node; two -> data = * (values + i); one -> next = two; two -> previous = one; } last = two; end_place = new Node; end_place -> data = NULL; end_place -> previous = end_place -> next = nullptr; last -> next = end_place; listsize = size; } // member functions // return size of list; O(1) int size() { return listsize; } // return true if list is empty, false otherwise; O(1) bool empty() { return (listsize == 0); } // returns an iterator pointing to the node at the desired position; O(n) iterator get(int position) { if (position < listsize / 2) { // the position is in the first half of the list iterator it = begin(); for (int i = 0; i < position; ++i) ++it; return it; } // the position is in the second half of the list iterator it(last); for (int i = 0; i < listsize - position - 1; ++i) --it; return it; } // edit the value of the node pointed to by the iterator; O(1) void edit(iterator it, Type value) { Node * node = * it; node -> data = value; } // push a new node to the front of the list; O(1) void push_front(Type value) { Node * newfront = new Node; newfront -> data = value; newfront -> next = first; first -> previous = newfront; newfront -> previous = nullptr; first = newfront; ++listsize; } // pop the front of the list if it is not empty, strong exception guarantee; O(1) void pop_front() { if (listsize == 0) { std::cerr << "Cannot pop empty list\n"; return; } if (listsize == 1) { delete first; return; } Node * newfirst = first -> next; delete first; first = newfirst; first -> previous = nullptr; --listsize; } // push a new node to the back of the list; O(1) void push_back(Type value) { Node * newback = new Node; newback -> data = value; newback -> previous = last; last -> next = newback; newback -> next = end_place; last = newback; ++listsize; } // pop the back of the list if it is not empty, strong exception guarantee; O(1) void pop_back() { if (listsize == 0) { std::cerr << "Cannot pop empty list\n"; return; } if (listsize == 1) { delete first; return; } Node * newlast = last -> previous; delete last; last = newlast; last -> next = nullptr; --listsize; } // insert a new node before the node pointed to by the iterator; O(1) void insert(iterator it, Type value) { if (it == begin()) { push_front(value); return; } if (it == end()) { push_back(value); return; } Node * before = & (* (--it)); ++it; Node * after = & (* (++it)); Node * inserted = new Node; inserted -> data = value; before -> next = inserted; after -> previous = inserted; inserted -> next = after; inserted -> previous = before; ++listsize; } // pop the node pointed to by it, strong exception guarantee void pop(iterator it) { if (it == begin()) { pop_front(); return; } if (it == end()) { pop_back(); return; } if (listsize == 0) { std::cerr << "Cannot pop empty list\n"; return; } if (listsize == 1) { delete first; return; } Node * before = * (--it); ++it; Node * after = * (++it); before -> next = after; after -> previous = before; Node * deletenode = * it; delete deletenode; } void reverse(iterator from, iterator to) { if (from == to) return; vector<Type> v; int cnt = 0; for (iterator it = from, end = to; it != end; ++it) { Node * curr = * it; v.push_back(curr.data); ++cnt; } std::reverse(v.begin(), v.end()); } void reverse() { reverse(begin(), end()); } UnorderedList operator + (UnorderedList & nextlist) { delete end_place; last -> next = nextlist.first; nextlist.first -> previous = last; return * this; } ~ UnorderedList () { Node * current = first; Node * next = current -> next; for (int i = 0; i < listsize; ++i) { delete current; current = next; next = current -> next; } delete first; delete last; delete end_place; } void display() { for (iterator it = begin(), eit = end(); it != eit; ++it) { Node * node = * it; cout << node -> data << (it == --eit ? "\n" : " <=> "); } } };
编译错误输出
* Executing task: C/C++: g++ build active file Starting build... /usr/bin/g++ -fdiagnostics-color=always -g /Users/ericssonlin/code/C++/template.cpp -o /Users/ericssonlin/code/C++/template /Users/ericssonlin/code/C++/template.cpp:43:43: 警告:别名声明是C++11扩展特性 [-Wc++11-extensions] using iterator_category = std::bidirectional_iterator_tag; ^ /Users/ericssonlin/code/C++/template.cpp:44:43: 警告:别名声明是C++11扩展特性 [-Wc++11-extensions] using difference_type = std::ptrdiff_t; ^ /Users/ericssonlin/code/C++/template.cpp:45:43: 警告:别名声明是C++11扩展特性 [-Wc++11-extensions] using value_type = Node; ^ /Users/ericssonlin/code/C++/template.cpp:46:43: 警告:别名声明是C++11扩展特性 [-Wc++11-extensions] using pointer = Node *; ^ /Users/ericssonlin/code/C++/template.cpp:47:43: 警告:别名声明是C++11扩展特性 [-Wc++11-extensions] using reference = Node &; ^ /Users/ericssonlin/code/C++/template.cpp:245:33: 错误:成员引用的基类型'UnorderedList::Node *'不是结构体或联合体 v.push_back(curr.data); ~~~~^~~~~ /Users/ericssonlin/code/C++/template.cpp:274:24: 错误:无法将'UnorderedList<int>::Node'类型转换为'UnorderedList<int>::Node *'类型 Node * node = * it; ^ ~~~~ /Users/ericssonlin/code/C++/template.cpp:284:10: 注:在实例化成员函数'UnorderedList<int>::display'时请求 list.display(); ^ /Users/ericssonlin/code/C++/template.cpp:53:50: 错误:无法将无关类型'UnorderedList<int>::Node *'绑定到'UnorderedList<int>::Node'的非const左值引用 reference operator * () { return n_ptr; } ^~~~~ /Users/ericssonlin/code/C++/template.cpp:274:31: 注:在实例化成员函数'UnorderedList<int>::iterator::operator*'时请求 Node * node = * it; ^ /Users/ericssonlin/code/C++/template.cpp:284:10: 注:在实例化成员函数'UnorderedList<int>::display'时请求 list.display(); ^ /Users/ericssonlin/code/C++/template.cpp:244:24: 错误:无法将'UnorderedList<int>::Node'类型转换为'UnorderedList<int>::Node *'类型 Node * curr = * it; ^ ~~~~ /Users/ericssonlin/code/C++/template.cpp:251:13: 注:在实例化成员函数'UnorderedList<int>::reverse'时请求 reverse(begin(), end()); ^ /Users/ericssonlin/code/C++/template.cpp:290:10: 注:在实例化成员函数'UnorderedList<int>::reverse'时请求 list.reverse(); ^ /Users/ericssonlin/code/C++/template.cpp:230:20: 错误:无法将'UnorderedList<int>::Node'类型转换为'UnorderedList<int>::Node *'类型 Node * before = * (--it); ^ ~~~~~~~~ /Users/ericssonlin/code/C++/template.cpp:294:10: 注:在实例化成员函数'UnorderedList<int>::pop'时请求 list.pop(it); ^ /Users/ericssonlin/code/C++/template.cpp:232:20: 错误:无法将'UnorderedList<int>::Node'类型转换为'UnorderedList<int>::Node *'类型 Node * after = * (++it); ^ ~~~~~~~~ /Users/ericssonlin/code/C++/template.cpp:235:20: 错误:无法将'UnorderedList<int>::Node'类型转换为'UnorderedList<int>::Node *'类型 Node * deletenode = * it; ^ ~~~~ 生成5个警告和7个错误。 Build finished with error(s). * The terminal process failed to launch (exit code: -1). * Terminal will be reused by tasks, press any key to close it.
错误修复方案
1. 修正迭代器operator*的返回类型
迭代器的reference定义为Node&,但原代码返回的是Node*(n_ptr),类型不匹配,导致后续解引用迭代器得到Node对象,无法直接赋值给Node*变量。
修改operator*实现:
reference operator * () { return *n_ptr; }
2. 修正迭代器解引用的使用方式
所有试图将*it直接赋值给Node*的代码,需要改为取引用的地址:
display函数:Node * node = &(*it);reverse函数:Node * curr = &(*it);pop函数:Node * before = &(*(--it));、Node * after = &(*(++it));、Node * deletenode = &(*it);
3. 修正指针成员访问语法
curr是Node*类型,访问成员必须用->而非.:
v.push_back(curr->data);
4. 解决C++11扩展警告
编译时添加-std=c++11或更高版本的编译选项(如-std=c++17),启用C++11及以上标准。
5. 修复其他潜在逻辑错误
- 构造函数空指针访问:
UnorderedList(int size)中初始one为nullptr,循环中会触发空指针访问,重构构造逻辑:
UnorderedList(int size) { listsize = size; if (size == 0) { first = last = nullptr; end_place = new Node; return; } first = new Node; Node* prev = first; for (int i = 1; i < size; ++i) { Node* curr = new Node; prev->next = curr; curr->previous = prev; prev = curr; } last = prev; end_place = new Node; last->next = end_place; end_place->previous = last; }
- 析构函数重复删除:原析构函数重复删除
first、last,且空列表时会触发空指针,重构析构:
~UnorderedList() { Node* current = first; while (current != end_place) { Node* next = current->next; delete current; current = next; } delete end_place; }
operator+逻辑错误:原实现会修改当前对象并删除end_place,导致
相关产品推荐
相关产品推荐

