• STL源码阅读(四)


    STL源码阅读(四) (SGI STL v3.3)

    stl_deque.h (<deque>)

    // deque的内存管理,分配一段内存_M_map用来存储指向缓存区域的指针,每当缓存区域buffer不足时,分配一段新的缓存区域,然后
    // 将指向该区域的指针添加到_M_map中。buffer大小的分配原则是,当sizeof(_Tp) > 512时,分配的缓存大小sizeof(_Tp);否则,
    // 分配的缓存大小为sizeof(_Tp) * (512 / sizeof(_Tp));
    
    template <class _Tp, class _Alloc, bool __is_static>
    class _Deque_alloc_base;   // 每个类中保留两个分配器对象,_M_map_allocator, _M_node_allocator
    template <class _Tp, class _Alloc>
    class _Deque_alloc_base<_Tp, _Alloc, true>; // 使用静态内存分配器 {
    ...
        _Tp** _M_map;   // 指向缓存结点的指针
        size_T _M_map_size; // map的大小
    ...
    }
    // deque迭代器,迭代器类型随机迭代器random_access_iterator_tag。
    template <class _Tp, class _Ref, class _Ptr>
    struct _Deque_iterator {
    ...
        // 迭代器中维护四个指针
        _Tp* _M_cur;        // 指向当前缓存区域已用空间的最后一个元素
        _Tp* _M_first;      // 指向当前缓存区域的开始
        _Tp* _M_last;       // 指向当前缓存区域的末尾
        _Map_pointer _M_node;   // 指向当前正在使用的那一个缓存区域
    ...
    }
    
    // 注意迭代器迭代元素的方式,迭代器所处理的内存空间从整体上看不是连续的,但从局部看是连续的
    // 计算迭代器的差值
    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+=(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;
    }
    
    // deque基类
    template <class _Tp, class _Alloc>
    class _Deque_base
      : public _Deque_alloc_base<_Tp,_Alloc, _Alloc_traits<_Tp, _Alloc>::_S_instanceless> {
      ...
          typedef _Deque_iterator<_Tp,_Tp&,_Tp*>             iterator;
        // 除了从_Deque_alloc_base继承过来的数据成员,还维护两个迭代器,分别指向元素的首部和尾部
        iterator _M_first;  // 指向第一个元素
        iterator _M_finish; // 指向最后一个元素的下一个元素
    
        enum { _S_initial_map_size = 8 }; // _M_map的初始大小为8
    
      ...  
    }
    
    // 初始化__num_elements个节点,最小结点数8个
    template <class _Tp, class _Alloc>
    void
    _Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements)
    {
      size_t __num_nodes = 
        __num_elements / __deque_buf_size(sizeof(_Tp)) + 1;
    
      _M_map_size = max((size_t) _S_initial_map_size, __num_nodes + 2);
      _M_map = _M_allocate_map(_M_map_size);    // 当多分配两个结点
    
        // 指向_M_map的最中间,向头部和尾部的扩展能力相同
      _Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2;
      _Tp** __nfinish = __nstart + __num_nodes;
    
      __STL_TRY {
        _M_create_nodes(__nstart, __nfinish);   // 为每个结点分配内存
      }
      __STL_UNWIND((_M_deallocate_map(_M_map, _M_map_size), 
                    _M_map = 0, _M_map_size = 0));
      _M_start._M_set_node(__nstart);
      _M_finish._M_set_node(__nfinish - 1);
      _M_start._M_cur = _M_start._M_first;
      _M_finish._M_cur = _M_finish._M_first +
                   __num_elements % __deque_buf_size(sizeof(_Tp));
    }
    
    template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
    class deque : protected _Deque_base<_Tp, _Alloc>;
    
    // 注意swap的实现
    void swap(deque& __x) {
        __STD::swap(_M_start, __x._M_start);
        __STD::swap(_M_finish, __x._M_finish);
        __STD::swap(_M_map, __x._M_map);
        __STD::swap(_M_map_size, __x._M_map_size);
    }
    
    // 当push_front, push_back, insert, resize添加元素超出原空间时,需要
    // 重新分配空间map,将原来的_M_map拷贝到新map中,并没有copy缓冲区的元素
    template <class _Tp, class _Alloc>
    void deque<_Tp,_Alloc>::_M_reallocate_map(size_type __nodes_to_add,
                                              bool __add_at_front)
    {
      size_type __old_num_nodes = _M_finish._M_node - _M_start._M_node + 1;
      size_type __new_num_nodes = __old_num_nodes + __nodes_to_add;
    
      _Map_pointer __new_nstart;
      if (_M_map_size > 2 * __new_num_nodes) {
        __new_nstart = _M_map + (_M_map_size - __new_num_nodes) / 2 
                         + (__add_at_front ? __nodes_to_add : 0);
        if (__new_nstart < _M_start._M_node)
          copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart);
        else
          copy_backward(_M_start._M_node, _M_finish._M_node + 1, 
                        __new_nstart + __old_num_nodes);
      }
      else {
        size_type __new_map_size = 
          _M_map_size + max(_M_map_size, __nodes_to_add) + 2;
    
        _Map_pointer __new_map = _M_allocate_map(__new_map_size);
        __new_nstart = __new_map + (__new_map_size - __new_num_nodes) / 2
                             + (__add_at_front ? __nodes_to_add : 0);
        copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart);
        _M_deallocate_map(_M_map, _M_map_size);
    
        _M_map = __new_map;
        _M_map_size = __new_map_size;
      }
    
      _M_start._M_set_node(__new_nstart);
      _M_finish._M_set_node(__new_nstart + __old_num_nodes - 1);
    }
    

    参考资料

    1. sgi STL
    2. cppreference.com
  • 相关阅读:
    2012 Multi-University #8
    2016"百度之星"
    Codeforces Round #352 (Div. 2)
    数位DP CF 55D Beautiful numbers
    数位DP GYM 100827 E Hill Number
    2012 Multi-University #9
    2012 Multi-University #10
    java生成指定范围的随机数
    MySql查询时间段的方法
    eclipse报错GC overhead limit exceed,卡顿
  • 原文地址:https://www.cnblogs.com/corfox/p/6063305.html
Copyright © 2020-2023  润新知