我执行std :: list的迭代器不起作用

时间:2016-04-19 12:41:10

标签: c++ templates c++11 linked-list iterator

我正在尝试编写像std :: list one这样的列表模板。 这是我在List.h中的代码:

#include <memory>
#include <cassert>
#include <iterator>

template<typename T, class Node>
class iterator : public std::iterator<std::bidirectional_iterator_tag, Node *, Node &> {
    Node *underlying;

public:
    explicit iterator(Node *n) : underlying(n) { };

    iterator() : underlying(nullptr) { };

    iterator &operator++() { //preinc
    assert(underlying != nullptr && "Out-of-bounds iterator increment!");
    underlying = underlying->next;
    return *this;
    }

    iterator operator++(int) { //postinc
    assert(underlying != nullptr && "Out-of-bounds iterator increment!");
    iterator temp(*this);
    ++(*this);
    return temp;
    }

    iterator &operator--() { //predec
    assert(underlying != nullptr && "Out-of-bounds iterator decrement!");
    underlying = underlying->previous;
    return *this;
    }

    iterator operator--(int) { //postdec
    assert(underlying != nullptr && "Out-of-bounds iterator decrement!");
    iterator temp(*this);
    --(*this);
    return temp;
    }

    bool operator==(const iterator &rhs) {
    return underlying == rhs.underlying;

    }

    bool operator!=(const iterator &rhs) {
    return underlying != rhs.underlying;

    }

    T &operator*() {
    return underlying->data;
    }
};

template<typename T>
class List {

    class Node {
    public:
    T data;
    Node *previous;
    Node *next; //is that T needed?
    Node(T &d) : data(d) { };
    };

private:

    Node *head; //first element
    Node *tail;

    void create() { head = tail = NULL; }

    void create(const List &rhs) {
    iterator this_iter = head;
    iterator rhs_iter = rhs.head;
    while (rhs_iter != NULL) {
        this_iter->data = (rhs_iter++)->data;
        ++this_iter;
    }
    };

public:
    typedef T *iterator;
    typedef const T *const_iterator;
    typedef size_t size_type;
    typedef T value_type;

    List() { create(); };

    List &operator=(const List &rhs) {
    if (&rhs != this) {
        create(rhs);
    }
    return *this;
    };

    List(const List &rhs) { create(rhs); };

    ~List() { while(head) remove(head); };

    T *begin() { return head; };

    T *end() { return tail; };

    T front() { return head->data; };

    T back() { return tail->data; };

    bool empty() { return head == NULL; }

    size_type size() {
    size_t i = 0;
    Node *node = head;
    while (node) {
        node = node->next;
        i++;
    }
    return i;
    };

    T &operator[](size_type i) {
    if (i < size() && i >= 0) {
        Node *temp = head;
        while (i > 0) {
            temp = temp->next;
            i--;
        }
        return temp->data;
    }
    throw std::out_of_range("Index out of range");
    };

//    const T &operator[](size_type i) const; //how to implement and do not duplicate code?

    Node *push_back(value_type data) {
    Node *n = new Node(data);
    if (head == NULL) {
        head = tail = n;
    } else {
        n->previous = tail;
        tail->next = n;
        tail = n;
    }
    return n;
    };

    Node *push_front(value_type data) {
    Node *n = new Node(data);
    if (head == NULL) {
        head = tail = n;
    } else {
        n->next = head;
        head->previous = n;
        head = n;
    }
    return n;
    };

    void pop_front() {
    remove(head);
    };

    void pop_back() {
    remove(tail);
    };

    void remove(Node *n){
    if(n == NULL) return;
    if(n == head){
        head = n->next;
        head->previous =NULL;
    }
    else if(n == tail){
        tail = n->previous;
        tail->next = NULL;
    }
    else{
        n->previous->next = n->next;
        n->next->previous = n->previous;
    }
    delete n;
    }


};

这是main.cpp

#include <iostream>
#include "List.h"
int main(){
    List<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    l.pop_back();
    l.pop_front();
    l.push_back(4);
    l.push_back(5);
    for (size_t i = 0; i < l.size(); i++)
        std::cout << l[i] << "\n";
    std::cout<<"Front "<<l.front();
    std::cout<<"Back "<<l.back();
}

实际上push_back / front,pop_back / front和[]运算符工作正常。但我得到“流程完成退出代码139” 我尝试使用front()或back()时出错。我知道列表模板的这个迭代器不起作用,但我知道如何将它组合起来。有人可以暗示或帮忙吗?

编辑: 好的,我已经修复了删除和front(),tail()方法的问题。但仍然是迭代器的东西不起作用。 例如这段代码:

for(List<int>::iterator it = l.begin(); it!=l.end(); it++){
        std::cout << it << "\n";
    }

给我错误:

error: cannot convert ‘List<int>::Node*’ to ‘List<int>::iterator {aka int*}’ in initialization
     for(List<int>::iterator it = l.begin(); it!=l.end(); it++){
                                          ^
error: comparison between distinct pointer types ‘List<int>::iterator {aka int*}’ and ‘List<int>::Node*’ lacks a cast [-fpermissive]
     for(List<int>::iterator it = l.begin(); it!=l.end(); it++){
                                                       ^

我知道问题在于使用迭代器模板包装节点,并且我有“typename T * iterator”。

2 个答案:

答案 0 :(得分:3)

您的beginend方法返回Node*,而不是您的迭代器类型。并且您创建了接受Node*作为参数explicit的迭代器构造函数;你告诉编译器禁止从List<int>::Node*List<int>::iterator的隐式转换。

您必须执行以下操作之一:

  1. explicit移除explicit iterator(Node *n) : underlying(n) { };(虽然这可能会在您不想要的情况下隐含转化)
  2. 更改beginend以返回iterator(head)iterator(tail)(执行显式转换为iterator)而不是head和{{1 (并将tailbegin的返回类型更改为end,无论如何都应该这样做。
  3. 您还有其他一些问题:

    1. 您不应该在iterator中完成typedef T* iterator;隐藏了List类的定义,因此iterator从未使用它。修复(并为List的使用添加必要的模板)使其编译
    2. iterator的继承定义应为iterator而不是template<typename T, class Node> class iterator : public std::iterator<std::bidirectional_iterator_tag, T>;后者声明解除引用的值应为template<typename T, class Node> class iterator : public std::iterator<std::bidirectional_iterator_tag, Node *, Node &>(当您希望它为Node *时,每个T中的值)
    3. Node应该返回end而不是iterator<T, Node>(nullptr);否则,如果要在终止循环之前打印iterator(tail),则在打印tail的值之前停止。
    4. 完成所有这些后,您应该编译并获得您期望的结果。代码仍有问题,例如

      1. 它不是tail正确的,并且不提供各种访问者的const版本,这可能会阻止优化;如果编译器无法确定循环实际非变异
      2. ,您可能最终会在每个循环上重新计算const
      3. 复制构造函数/赋值实用程序函数size不起作用(您想要反复迭代createrhs,您不能使用push_back推送新值
      4. 缺少iterator访问者意味着不能使效用函数起作用;它需要一个const迭代器类型来迭代const,并保证它不会违反rhs要求,但你只定义了变异迭代器函数
      5. 但是,你的代码中的性能优化和正确性是你没有运用的;一旦您对新代码感到满意,就可以解决这个问题。

        your code(虽然复制构造/分配的修复程序是使用const List&围绕缺少const_cast安全迭代的暴力破解的恶劣攻击);我还添加了几个测试来显示复制构造和分配工作。 Take a look

答案 1 :(得分:1)

问题(问题?)在remove():您不检查headNULLhead案例),如果{{1} {}} tail NULL {}} tailn->previous为空(通用案例)

我建议n->next

remove()