STL list的简单实现及list迭代器失效问题

上一篇我针对不同的数据结构来演示了迭代器的使用,今天我们主要来看看STL list的使用及他的模拟实现。
首先我们来实现list节点的结构体。看下面代码:

template<class T>
struct __ListNode
{
    T _data;
    __ListNode* _next;
    __ListNode* _prev;

    __ListNode(const T& x)  //节点的构造函数
        :_data(x),_next(NULL),_prev(NULL)
    {}
};

下面我们来看看迭代器的简单实现(注:这里只是实现他的简单基本功能,后面会进行完善)
迭代器结构中只有一个成员变量”Node* _node “(一个指向节点的指针),所以有一种说法就是说迭代器是一种对指针的封装。

template<class T,class Ref,class Ptr>  //T,T&,T*
struct __ListIterator
{
    typedef __ListNode<T> Node;
    typedef __ListIterator<T, Ref, Ptr> self;

    __ListIterator(Node* node)
        :_node(node)
    {}

    //重载*进行解引用,所以返回指针指向的数据的引用
    Ref operator*()  
    {
        return _node->_data;
    }

    //重载!=,看两个迭代器是否相等,只需看他的成员变量(指向节点的指针)是否相等,即是否指向同一个节点。
    bool operator!=(const self& s) const
    {
        return (_node != s._node);
    }

    bool operator==(const self& s) const
    {
        return (_node == s._node);
    }

    //重载++,就是将链表中节点的遍历访问和操作array元素时的指针接口一致。
    self& operator++()
    {
        _node = _node->_next;
        return *this;
    }

    self operator++(int)
    {
        /*self tmp(*this);
        _node = _node->_data;
        return tmp*/;

        //优化
        Node* cur = _node;
        _node = _node->_next;
        return self(cur);
    }

    self& operator--()
    {
        _node = _node->_prev;
        return *this;
    }

    self operator--(int)
    {
        Node* cur = _node;
        _node = _node->_prev;
        return self(cur);
    }

    Node* _node;
};

下面是STL中 , 容器list的简单实现

template<class T>
class List
{
    typedef __ListNode<T> Node;
public:
    typedef __ListIterator<T, T&, T*> Iterator;

    List()
    {
        _head = GetNode(T());
        _head->_next = _head;
        _head->_prev = _head;
    }

    ~List()
    {
        Clear();
        _head = NULL;
    }

    Node* GetNode(const T& x)  //创建新的节点
    {
        return(new Node(x));
    }

    void PushBack(const T& x)
    {
        Node* tmp = GetNode(x);
        Node* tail = _head->_prev;

        tmp->_prev = tail;
        tail->_next = tmp;

        tmp->_next = _head;
        _head->_prev = tmp;
    }

    void PopBack()
    {
        assert(!Empty());

        Node* tail = _head->_prev;
        Node* prev = tail->_prev;

        prev->_next = _head;
        _head->_prev = prev;
        delete tail;

    }

    void PushFront(const T& x)
    {
        Node* next = _head->_next;
        Node* tmp = GetNode(x);

        tmp->_next = next;
        next->_prev = tmp;
        tmp->_prev = _head;
        _head->_next = tmp;
    }

    void PopFront()
    {
        assert(!Empty());
        Node* tail = _head->_next;
        Node* next = tail->_next;

        _head->_next = next;
        next->_prev = _head;
    }

    bool Empty()
    {
        return (_head->_next == _head);
    }

    Iterator Find(const T& x)
    {
        /*Node* cur = _head->_next;
        while (cur != _head)
        {
            if (cur->_data == x)
            {
                return Iterator(cur);
            }
            cur = cur->next;
        }
        return _head;*/

        Iterator it = Begin();
        while (it != End())
        {
            if (*it == x)
            {
                return it;
            }
            it++;
        }
        return it;
    }
    //随机插入节点,是在给定位置pos后面插入
    void Insert(Iterator pos,const T& x)
    {
        assert(pos != End());

        Node* tail = GetNode(x);
        Node* next = (pos._node)->_next;
        Node* prev = (pos._node);

        tail->_next = next;
        next->_prev = tail;
        tail->_prev = prev;
        prev->_next = tail;
    }


    Iterator Erase(Iterator pos)
    {
        assert(pos != End() && pos._node);
        Node* prev = (pos._node)->_prev;
        Node* next = (pos._node)->_next;

        prev->_next = next;
        next->_prev = prev;

        delete pos._node;
        return Iterator(next);
    }

    void Clear()
    {
        Iterator it = Begin();
        while (it != End())
        {
            Node* cur = it._node;
            ++it;
            delete cur;
        }
        _head->_next = _head;
        _head->_prev = _head;
    }

    Iterator Begin()
    {
        return Iterator(_head->_next);
    }

    Iterator End()
    {
        return Iterator(_head);
    }

private:
    Node* _head;
};

下面我们来看一个问题:迭代器失效

向容器(list、vector等)中添加元素或删除元素的操作都可能会使指向容器元素的指针、引用或迭代器失效。这里只说list。

  1. 向list添加元素后:
    指向list的迭代器仍有效。即向list中添加元素不影响迭代器失效。
  2. 从list删除元素后:
    当我们从list删除一个元素后,指向该元素的迭代器会失效,其他位置不受影响。

看下面两段代码,都属于正确用法:

    List<int>::Iterator it = l.Begin();
    while (it != l.End())
    {
        if ((*it)%2)
        {
            it = l.Erase(it);返回删除元素的下一个元素的迭代器
        }
        else
        {
            it++;
        }
    }
List<int>::Iterator it = l.Begin();
    while (it != l.End())
    {
        if ((*it)%2)
        {
            l.Erase(it++);//删除it指向的元素后,迭代器it++
        }
        else
        {
            it++;
        }
    }

在调用Erase()后,不必递增迭代器,因为Erase返回的迭代器已经指向链表中的下一个元素。如果没有调用Erase(),则需要递增迭代器一次,使之移至下一个元素。所以这两句代码使用原则是:每次循环,有你没我

思考一下:
如果使用方法如下,该如何解决迭代器失效问题:

    List<int>::Iterator it = l.Begin();
    while (it != l.End())
    {
        if ((*it)%2)
        {
            l.Erase(it);
        }
            it++;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值