• STL(九)之iterator


    C++标准库(九)之iterator

    iterator

    iterator模式:提供一种方法,使之能依次访问容器内的各个元素,而又不暴露该聚合物内部的表述方式。
    STL的中心思想是将算法与数据结构分离,彼此独立设计,最后在用iterator将他们结合在一起,获得最大的适配性。

    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算法左闭右开的要求。

    迭代器定义

    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;
    }
    
    

    迭代器失效分析

    • 插入或者删除都不会导致迭代器失效

      deque

      设计理念

      deque允许在常数时间内对头端的元素进入插入或者删除,因为他是动态的以连续分段的空间组成的,访问的复杂度由迭代器去维护。这里的map是由一小块连续空间,其中每个元素都是指针,指向一小段连续空间,其中每个元素都是指针,指向另一段连续线性空间,成为缓冲区,默认值为512bytes。
      一个deque至少会管理8个节点,最多是“所需节点数+2”。在结点数已经用完的情况下,重新换一个map。
      删除或者插入的方式:如果清除/插入点之前的元素较少,就移动清除点之前的元素;反之,移动清除/插入点之后的元素

      迭代器定义

      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之后/之前的迭代器失效,根据前后元素量的多少决定。

      set和multiset

      设计理念

      在SGI STL中,set底层使用红黑树完成,set中所有的元素都是自动排列的,在set中:value = key,并且,set中的值不允许修改。
      set与multiset的区别在于使用红黑树的底层插入操作不同:insert_equal()insert_unique()

      迭代器定义

      迭代器的++和--操作是以中序遍历的过程进行的。
    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;
    };

    迭代器失效分析

    基本上删除和插入操作不会使迭代器失效。

  • 相关阅读:
    state estimation for robotics-1
    Linux命令----用户目录、路径
    Linux命令----系统目录结构
    Linux命令----shell
    socket php
    深入浅出讲解:php的socket通信 转
    phpstorm配置sftp自动上传
    linux下xdebug的安装和配置方法
    xdebug安装
    swoole 客户端和服务端不断通信
  • 原文地址:https://www.cnblogs.com/xcb-1024day/p/11332510.html
Copyright © 2020-2023  润新知