2016-11-09 8 views
0

私はいくつかの本の例やものに取り組んできましたが、この演習ではSTLリストの見た目を実装する方法を見つけました。私は何とかそれを作ったし、それはちょっとした作品ですが、実装に大きな欠陥があります。
最大のものは、List.end()イテレータをどのようにして動作させるのか全くわからないということです。
私はコードを最初に示して、次に私のアイデアの一部を伝えようとします。
カスタムSTLリスト実装の質問

#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()関数は、リストではなく最後過去1それが必要としての定期的な最後の要素を返す見ることができるように。
この部分を再加工して、* lastを最後のイテレータよりも後にして、実際のリストの終わりまでのポインタの必要を省略するために演算子+を使ってリストを反復処理する必要がありますか? (下記のコードのcorectnessわからない)このような何か:

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

しかし、私はそれがものが実際の実装でどのように動作するかだか分からない、すべての後に非常に厳しい可能性がループします。
私は、この物が既にそこにあり、すべてのことを知っています。それは教育的な目的のためのものなので、私はいくつかのアイデアを聞くことを願っています。前もって感謝します。

答えて

0

イテレータは、これまでのように「スマートポインタ」として知られていました。 (実際、ポインタはイテレータですが、反対ではありません)。だから、ポインタのようなイテレータを考えてみてください。

"最後を過ぎたもの"は、ベクトルを使って作業しているときの意味を明確に示しています。vectorには、その要素が連続したスペースに含まれています。実際、ポインタだけでベクトル反復子を実装することは可能です。しかし、リンクされたlistの場合はそうではありません。通常、その要素は連続したメモリにはありません。

あなたが倍増リンクリストとしてListクラスを実装しているので、私はあなたが頭でfirstlastポインタを変更することをお勧め:

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

ので、begin()イテレータは&headなっhead.nextend()イテレータになります。これはリストの最後の要素がheadを指している限り動作します。

ところでNode<T>を友達クラスのclassとして作成する必要はありません。これは単なる実装の詳細です。それをstructに変更し、実装namespaceに入れてください。