迭代器实现问题

时间:2011-12-17 22:43:14

标签: c++ stl iterator

在尝试使用类似内部STL的迭代器创建双向链表时,我编写了以下代码。我现在只提供带有非相关部分的头文件。

我的问题是......

  1. STL以某种方式使用迭代器 - 具体来说,您从.begin()迭代器中导航到STL容器,但不包括.end()迭代器。要做到这一点,.end()迭代器必须是容器末尾的一个。考虑到我的开始,我将如何实现这种语义(这是主要问题)?

  2. 接口中是否有任何缺失(关于迭代器类和应该存在的东西)?

  3. 以下是代码:

    template <typename T>
    class Node
    {
        T data;
        Node<T>* next;
        Node<T>* prev;
    };
    
    template <typename T>
    class LinkedList
    {
        public:
    
            class Iterator
            {
                public:
    
                    Iterator() {}
                    explicit Iterator(const Node<T>& init) { current = init; }
    
                    //Dereference operator - return the current node's data.
                    inline T& operator*() { return current->data; }
    
                    //Prefix returns by reference.
                    inline Iterator& operator++()   { current = current->next; return *this; } 
                    inline Iterator& operator--()   { current = current->prev; return *this; }
    
                    //Postfix returns non-reference and has int parameter to differentiate function signature.
                    inline Iterator operator++(int) { Iterator res = *this; current = current->next; return res; }
                    inline Iterator operator--(int) { Iterator res = *this; current = current->prev; return res; }
    
                private:
    
                    Node<T>* current;
            };
    
            Iterator begin() { return Iterator(m_start); }
            Iterator end()   { return Iterator(m_end);   }
    
        private:
            Node<T>* m_start;
            Node<T>* m_end;
    };
    

    我知道我可能会或者可能没有使用++ / - 运算符的问题,但这并不会让我感到特别烦恼,因为当我有足够的代码对此进行一些测试时,我会解决这些问题。 。如果您愿意,请随意提示:)

3 个答案:

答案 0 :(得分:2)

  1. end()返回的迭代器必须是可递减的,否则您无法反向迭代列表。 你可以通过让Iterator存储两个指针来实现这一点:当前节点(结束时为NULL)和前一个节点(允许你找到包含数据的最后一个节点,即使是current == NULL。 / p>

    class Iterator
    {
        public:
    
            Iterator() {}
            explicit Iterator(Node<T>* curr, Node<T>* prev):
                current(curr), previous(prev) {}
    
            //Dereference operator - return the current node's data.
            inline T& operator*() { return current->data; }
    
            //Prefix returns by reference.
            inline Iterator& operator++()   
            { 
                previous = current;
                current = current->next; 
                return *this; 
            } 
            inline Iterator& operator--()   
            { 
                current = previous; 
                previous = current->previous;
                return *this; 
            }
    
            //Postfix should be implemented in terms of prefix operators
            inline Iterator operator++(int) { Iterator res = *this; ++*this; return res; }
            inline Iterator operator--(int) { Iterator res = *this; --*this; return res; }
    
        private:
    
            Node<T>* current;
            Node<T>* previous;
    };
    
    Iterator begin() { return Iterator(m_start, 0); }
    Iterator end()   { return Iterator(0, m_end);   }
    

    或者,您可以让列表包含指定列表“一个接一个结尾”的标记节点。但是,此节点不应具有数据成员。这可以通过将Node类拆分为非模板库来实现,只需指向下一个节点和上一个节点。

    例如,看起来GCC的列表实现存储了一个指向sentinel的指针,因此它的next指向列表中的第一个项目,而它的prev指向列表中的最后一个项目(如果列表为空,则两者都指向自身。)

  2. 您缺少operator->operator==operator!=,分类typedef可以从std::iterator继承,const_iterator实现(迭代器应该可以隐式转换)到const_iterator)。

答案 1 :(得分:1)

  1. 第一个节点的上级指针为NULL,最后一个节点的下一个指针也是如此。一个接一个的current指针将为NULL。

  2. operator->

答案 2 :(得分:1)

  1. 我认为NULL非常适合这里。
  2. 您可能希望编写类似for (iterator it = list.begin(); it != list.end(); it++)的内容,因此您也需要定义比较运算符。