C++標準庫(七)之iterator

iterator

iterator模式:提供一種方法,使之能依次訪問容器內的各個元素,而又不暴露該聚合物內部的表述方式。
STL的中心思想是將算法與數據結構分離,彼此獨立設計,最後在用iterator將他們結合在一塊兒,得到最大的適配性。node

vector

設計理念

vector是動態空間,隨着元素的加入,內部機制會自動擴充空間以容納新元素。vector的實現技術核心在於:對容器大小的控制以及從新配置時數據的移動效率
空間配置策略:在原容器無可用空間時,將容器大小擴展爲原先的兩倍,而後將原先的數據copy,在copy的數據後面構造新元素。
數據移動效率:根據是否爲POD類型判斷移動數據的成本,並想進一切方法減小數據移動的次數,源碼中有詳解。算法

迭代器定義

vector在進行萃取的時候,會使用萃取提供的特化版本:template<typename T> struct iterator_traits<T*> {}數據結構

template<typename T,class Alloc=alloc>
class vector
{
    public:
        typedef T value_type;
        typedef value_type* pointer;
        typedef value_type* iterator;
        typedef value_type& reference;
        typedef size_t size_type;
        typedef ptrdiff_t difference_type;
    
    protected:
        iterator begin;
        iterator end;        //使用空間的尾部
        iterator end_of_storage;        //可用空間的尾部
};

迭代器失效分析

  • 增長/刪除當前的iterator,當前iterator後面的iterator都會失效
  • 當增長元素的時候,由於擴容,可能會使原先的迭代器所有失效

list

設計理念

SGI STL的list是不只是雙向鏈表,仍是一個環形鏈表,存在一個額外的尾部結點,遵照STL算法左閉右開的要求。app

迭代器定義

template<typename T>
struct __list_node
{
    typedef void* void_pointer;
    void_pointer prev;
    void_pointer next;
    T data;
};

template<typename T,typename ref,typename ptr>
struct __list_iterator
{
    typedef __list_iterator<T,T&,T*> iterator;
    typedef __list_iterator<T,ref,ptr> self;
    typedef bidirectional_iterator_tag iterator_category;
    typedef T value;
    typedef ptr pointer;
    typedef ref reference;
    typedef __list_node<T>* link_type;    
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    link_type node;
    __list_iterator(link_type type) : node(type) {};
    __list_iterator() {};
    __list_iterator(const __list_iterator& iter) : node(iter.node) {};
    
    bool operator==(const self& iter) const  {return iter.node == node;};
    bool operator!=(const self& iter) const {return iter.node != node;};
    reference operator*() const {return ((*node).data;};
    pointer operator->() const {return &(operator*());};
    
    self& operator++()
    {
        node = (link_type)((*node).next);
        return *this;
    }
    
    slef operator++(int)
    {
        self temp = *this;
        ++*this;
        return temp;
    }

    self& operator()
    {
        node = (link_type)((*node).prev);
        return *this;
    }
    
    slef operator++(int)
    {
        self temp = *this;
        --*this;
        return temp;
    }
}

template<typename T,class Alloc=alloc>
class list
{
protected:
    typedef void* _Void_pointer;

public:      
    typedef _Tp value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef _List_node<_Tp> _Node;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

public:
    typedef _List_iterator<_Tp,_Tp&,_Tp*>             iterator;
    typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
}

迭代器失效分析

  • 插入或者刪除都不會致使迭代器失效less

    deque

    設計理念

    deque容許在常數時間內對頭端的元素進入插入或者刪除,由於他是動態的以連續分段的空間組成的,訪問的複雜度由迭代器去維護。這裏的map是由一小塊連續空間,其中每一個元素都是指針,指向一小段連續空間,其中每一個元素都是指針,指向另外一段連續線性空間,成爲緩衝區,默認值爲512bytes。
    一個deque至少會管理8個節點,最可能是「所需節點數+2」。在結點數已經用完的狀況下,從新換一個map。
    刪除或者插入的方式:若是清除/插入點以前的元素較少,就移動清除點以前的元素;反之,移動清除/插入點以後的元素dom

    迭代器定義

    deque是連續分段空間,維持其在「總體連續」假象的任務,落在了迭代器operator++和operator--兩個運算子身上。
template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator 
{
    typedef _Deque_iterator<_Tp, _Tp&, _Tp*>             iterator;
    typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
    static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }

    typedef random_access_iterator_tag iterator_category;
    typedef _Tp value_type;
    typedef _Ptr pointer;
    typedef _Ref reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef _Tp** _Map_pointer;

    typedef _Deque_iterator _Self;

    _Tp* _M_cur;
    _Tp* _M_first;
    _Tp* _M_last;
    _Map_pointer _M_node;

    _Deque_iterator(_Tp* __x, _Map_pointer __y) 
    : _M_cur(__x), _M_first(*__y),
      _M_last(*__y + _S_buffer_size()), _M_node(__y) {}
  
    _Deque_iterator() : _M_cur(0), _M_first(0), _M_last(0), _M_node(0) {}
    
    _Deque_iterator(const iterator& __x)
    : _M_cur(__x._M_cur), _M_first(__x._M_first), 
      _M_last(__x._M_last), _M_node(__x._M_node) {}

    reference operator*() const { return *_M_cur; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
    pointer operator->() const { return _M_cur; }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

    difference_type operator-(const _Self& __x) const 
    {
        return difference_type(_S_buffer_size()) * (_M_node - __x._M_node - 1) + (_M_cur - _M_first) + (__x._M_last - __x._M_cur);
    }

    _Self& operator++() 
    {
        ++_M_cur;
        if (_M_cur == _M_last) 
        {
            _M_set_node(_M_node + 1);
            _M_cur = _M_first;
        }   
        return *this; 
    }
    
    _Self operator++(int)  
    {
        _Self __tmp = *this;
        ++*this;
        return __tmp;
    }

    _Self& operator--() 
    {
        if (_M_cur == _M_first) 
        {
        _M_set_node(_M_node - 1);
        _M_cur = _M_last;
        }
        --_M_cur;
        return *this;
    }
    _Self operator--(int) 
    {
        _Self __tmp = *this;
        --*this;
        return __tmp;
    }

    _Self& operator+=(difference_type __n)
    {
        difference_type __offset = __n + (_M_cur - _M_first);
        if (__offset >= 0 && __offset < difference_type(_S_buffer_size()))
        _M_cur += __n;
        else 
        {
            difference_type __node_offset = __offset > 0 ? __offset / difference_type(_S_buffer_size()) : -difference_type((-__offset - 1) / _S_buffer_size()) - 1;
            _M_set_node(_M_node + __node_offset);
            _M_cur = _M_first + 
            (__offset - __node_offset * difference_type(_S_buffer_size()));
        }
        return *this;
    }

    _Self operator+(difference_type __n) const
    {
        _Self __tmp = *this;
        return __tmp += __n;
    }

    _Self& operator-=(difference_type __n) { return *this += -__n; }
 
    _Self operator-(difference_type __n) const 
    {
        _Self __tmp = *this;
        return __tmp -= __n;
    }

    reference operator[](difference_type __n) const { return *(*this + __n); }

    bool operator==(const _Self& __x) const { return _M_cur == __x._M_cur; }
    bool operator!=(const _Self& __x) const { return !(*this == __x); }
    bool operator<(const _Self& __x) const 
    {
        return (_M_node == __x._M_node) ? (_M_cur < __x._M_cur) : (_M_node < __x._M_node);
    }
  
    bool operator>(const _Self& __x) const  { return __x < *this; }
    bool operator<=(const _Self& __x) const { return !(__x < *this); }
    bool operator>=(const _Self& __x) const { return !(*this < __x); }

    void _M_set_node(_Map_pointer __new_node) 
    {
        _M_node = __new_node;
        _M_first = *__new_node;
        _M_last = _M_first + difference_type(_S_buffer_size());
    }
};

template <class _Tp, class _Ref, class _Ptr>
inline _Deque_iterator<_Tp, _Ref, _Ptr>
operator+(ptrdiff_t __n, const _Deque_iterator<_Tp, _Ref, _Ptr>& __x)
{
    return __x + __n;
}

template<typename T,typename Alloc=alloc,size_t Bufsize = 0>
class deque
{
    public:
        typedef T value_type;
        typede value_type* pointer;
        typedef size_t size_type;
        typedef __deque_iterator<T,T&,T*,BufSize> iterator;
        
    protected:
        typedef pointer* map_pointer;
        iterator begin;
        iterator end;
        map_iterator map;
        size_type map_size;
}

迭代器失效分析

  • 插入時,可能會更換map,使得存在的全部迭代器失效
  • 刪除時,使當前iterator以後/以前的迭代器失效,根據先後元素量的多少決定。ide

    set和multiset

    設計理念

    在SGI STL中,set底層使用紅黑樹完成,set中全部的元素都是自動排列的,在set中:value = key,而且,set中的值不容許修改。
    set與multiset的區別在於使用紅黑樹的底層插入操做不一樣:insert_equal()insert_unique()this

    迭代器定義

    迭代器的++和--操做是以中序遍歷的過程進行的。
template<typename Key, typename Compare = less<Key>, class Alloc = alloc>
class set
{
    public:
        typedef Key key_type;
        typedef Key value_type;
        typedef rb_tree<key_type,value_type,identity<value_type>,key_compare,Alloc> rep_type; 

        typedef typename rep_type::const_pointer pointer;
        typedef typename rep_type::const_pointer const_pointer;
        typedef typename rep_type::const_reference reference;
        typedef typename rep_type::const_reference const_reference;
        typedef typename rep_type::const_iterator iterator;
        typedef typename rep_type::const_iterator const_iterator;
    
    private:
        rep_type rep;
}

迭代器失效分析

基本上刪除和插入操做都不會使迭代器失效。設計

map和multimap

設計理念

在SGI STL中,map底層使用紅黑樹完成。全部的元素都會根據元素的鍵值自動排序。map的全部元素都是pair,同時擁有value可key。
map與multimap的區別在於使用紅黑樹的底層插入操做不一樣:insert_equal()insert_unique()指針

迭代器定義

迭代器的++和--操做是以中序遍歷的過程進行的。

template<typename T1,typename T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;
    
    T1 first;
    T2 second;
};

template<typename Key,typename Value,typename Compare = less<Key>, class Alloc=alloc>
class map
{
    public:
        typedef Key key_type;
        typedef Value value_type;
        typedef Value mapped_type;
        typedef pair<const Key,Value> value_type;
        typedef Compare key_conpare;

        typedef rb_tree<key_type,value_type,select1st<value_type>,key_compare,Alloc> rep_type;
        
        typedef typename rep_type::pointer pointer;
        typedef typename rep_type::const_pointer const_pointer;
        typedef typaneme rep_type::iterator iterator;
        typedef typaneme rep_type::const_iterator const_iterator;
    private:
        rep_type rep;
};

迭代器失效分析

基本上刪除和插入操做不會使迭代器失效。

相關文章
相關標籤/搜索