自定义STL列表实现问题

时间:2016-11-09 04:32:22

标签: c++ stl

好的,所以我一直在研究一些书籍的例子和内容,并发现这个练习实现了STL List。我已经以某种方式做到了它有点工作,但我在实施中遇到了一些重大缺陷。
最大的一点就是我完全不知道如何使我的List.end()迭代器按照它应该做的那样工作。
我想我会先显示代码,然后尝试告诉我的一些想法。

    #ifndef TESTS_LST_H
    #define TESTS_LST_H

    #include <memory>
    #include <cstddef>

    template<class T> class Node;
    template<class T> class ListIter;

    template<class T>
    class List {
    public:
    typedef ListIter<T> iterator;
    typedef const ListIter<T> const_iterator;
    typedef std::size_t size_type;


    List(): first(0), last(0), sz(0) {}
    List(const List<T>& lst);
    ~List() { clear(); }

    iterator begin() { return iterator(first); }
    iterator end()   { return iterator(last); }
    iterator insert() {}
    iterator erase() {}
    const_iterator begin() const { return iterator(first); }
    const_iterator end() const   { return iterator(last); }

    void push_back(const T& val);
    void push_front(const T& val);
    void clear();
    void pop_front();
    void pop_back();
    size_type size() { return sz; }
    bool empty() { return sz == 0; }


    List& operator=(const List& l);
    private:
        Node<T>* first;
    Node<T>* last;
    size_type sz;

    std::allocator<Node<T>>* alloc;
    };

    template<class T>
    class Node {
    public:
        Node(): next(0), prev(0), value(0) {}
        Node(const T& val): next(0), prev(0), value(val) {}

    private:
        Node<T>* next;
        Node<T>* prev;
        T value;

    friend class List<T>;
    friend class ListIter<T>;
    };

    template<class T>
    class ListIter {
    public:
    typedef ListIter<T> iterator;

    ListIter(Node<T>* iter): current_node(iter) {}
    ListIter(): current_node(0) {}
    ListIter(ListIter<T>* iter): current_node(iter->current_node) {}

    inline T& operator*() { return current_node->value; }
    iterator& operator=(const iterator& rhs) { *this->current_node = rhs.current_node; }
    bool operator==(const iterator& rhs) { return current_node->value == rhs.current_node->value; }
    bool operator!=(const iterator& rhs) { return current_node->value != rhs.current_node->value; }
    iterator& operator++();
    iterator operator++(int);
    iterator& operator--();
    iterator operator--(int);

    private:
        Node<T>* current_node;
        friend class List<T>;
    };

    template<class T>
    void List<T>::push_back(const T& val)
    {
    Node<T>* temp = alloc->allocate(1);
    alloc->construct(temp, val);
    if (first == 0) {
        first = last = temp;
    } else {
        temp->prev = last;
        last->next = temp;
        last = temp;
    }
    sz++;
    }

    template<class T>
    void List<T>::push_front(const T &val)
    {
        Node<T>* temp = alloc->allocate(1);
        alloc->construct(temp, val);
    if (first == 0) {
        first = last = temp;
    } else {
        temp->prev = 0;
        temp->next = first;
        first->prev = temp;
        first = temp;
    }
    sz++;
    }

    template<class T>
    void List<T>::clear()
    {
        Node<T>* current = first;
        while (current != 0) {
        Node<T>* next = current->next;
        //delete current
        alloc->deallocate(current, 1);
        alloc->destroy(current);
        current = next;
    }
    first = last = 0;
    sz = 0;
    }

    template<class T>
    List<T>::List(const List &lst)
    {
    first = last = 0;
    sz = 0;
    for (auto it = lst.begin(); it != lst.end(); it++) {
        push_back(it.current_node->value);
    }
    push_back(lst.last->value);
    }

    template<class T>
    List<T>& List<T>::operator=(const List &lst)
    {
    first = last = 0;
    sz = 0;
    for (auto it = lst.begin(); it != lst.end(); ++it) {
        push_back(it.current_node->value);
    }
    push_back(lst.last->value);
    return *this;
    }

template<class T>
void List<T>::pop_front()
{
    first = first->next;
    alloc->deallocate(first->prev, 1);
    alloc->destroy(first->prev);
    first->prev = 0;
    sz--;
}

template<class T>
void List<T>::pop_back()
{
    last = last->prev;
    alloc->deallocate(last->next, 1);
    alloc->destroy(last->next);
    last->next = 0;
    sz--;
}

template<class T>
ListIter<T>& ListIter<T>::operator++()
{
    current_node = current_node->next;
    return *this;
}

template<class T>
ListIter<T>& ListIter<T>::operator--()
{
    current_node = current_node->prev;
    return *this;
}

template<class T>
ListIter<T> ListIter<T>::operator++(int)
{
    iterator tmp(*this);
    ++*this;
    return tmp;
}

template<class T>
ListIter<T> ListIter<T>::operator--(int)
{
    iterator tmp(*this);
    --*this;
         return tmp;
    }

    #endif //TESTS_LST_H

正如你所看到的.end()函数返回列表的常规最后一个元素,而不是它应该返回的结尾。
我是否应该尝试重新编写这一部分,以便将* last保留为结束迭代器之后的一个,并使用operator +迭代列表以省略指向实际列表末尾的指针的需要?  这样的事情(不确定下面代码的核心性):

iterator& operator+(std::size_type n) 
{
    for (auto i = 0; i < n; ++i) {
        ++*this;
    }
    return *this;
}

但是我不确定这些东西在实际实现中是如何工作的,毕竟循环可能非常苛刻。 我知道这些东西已经存在并且可以正常工作。这只是出于教育目的,所以我希望听到一些想法。提前谢谢。

1 个答案:

答案 0 :(得分:0)

Iterator在过去被称为&#34;智能指针&#34;,因为它们就是这样的。 (实际上,指针是迭代器,但不是反对者)。所以,想一个像指针一样的迭代器。

&#34;一个接一个结束&#34;很清楚当你使用向量时意味着什么:vector在连续的空间中包含它的元素。实际上,可以用指针实现向量迭代器。但是对于链接的list来说情况并非如此,其中元素通常不在连续的内存中。

由于您已将List类实现为双重链接列表,因此建议您更改firstlast指针:

template<class T>
class List {
// ...
private:
    Node<T> head;
    size_type sz;
};

因此,begin()迭代器变为head.nextend()迭代器变为&head。这可以用于列表中的最后一个元素指向head

顺便说一句:您不需要在朋友课程中创建Node<T>作为class。这只是一个实现细节。将其更改为struct并将其放入实施namespace