STL源码阅读-deque

来源:互联网 发布:js的slice方法 编辑:程序博客网 时间:2024/05/07 21:48

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">vector提供单向开口的线性空间,而deque提供的则是双向开口的连续线性空间,当然这种线性空间并不是真正连续的。 deque允许于常数时间内对起痘团进行元素的插入或者移除操作,并且没有所谓的容量(capacity)的概念,以动态的分段连续内存空间组合而成,随时可以增加一段新的空间并连接起来。</span>

deque实现这种连续空间的组合,关键在于有一个中央控制器,从而对外呈现一个完整的整体。

去掉比较繁琐的typedef以及其他比较关键的函数的deque的定义如下,:

template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >class deque : protected _Deque_base<_Tp, _Alloc> {  // requirements:  __STL_CLASS_REQUIRES(_Tp, _Assignable);  typedef _Deque_base<_Tp, _Alloc> _Base;public:                         // Basic types  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 size_t size_type;  typedef ptrdiff_t difference_type;  typedef typename _Base::allocator_type allocator_type;  allocator_type get_allocator() const { return _Base::get_allocator(); }public:                         // Iterators  typedef typename _Base::iterator       iterator;  typedef typename _Base::const_iterator const_iterator;#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION  typedef reverse_iterator<const_iterator> const_reverse_iterator;  typedef reverse_iterator<iterator> reverse_iterator;#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */  typedef reverse_iterator<const_iterator, value_type, const_reference,                            difference_type>            const_reverse_iterator;  typedef reverse_iterator<iterator, value_type, reference, difference_type>          reverse_iterator; #endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */protected:                      // Internal typedefs  typedef pointer* _Map_pointer;  static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }protected:public:                         // Basic accessors  iterator begin() { return _M_start; }  iterator end() { return _M_finish; }  const_iterator begin() const { return _M_start; }  const_iterator end() const { return _M_finish; }  reverse_iterator rbegin() { return reverse_iterator(_M_finish); }  reverse_iterator rend() { return reverse_iterator(_M_start); }  const_reverse_iterator rbegin() const     { return const_reverse_iterator(_M_finish); }  const_reverse_iterator rend() const     { return const_reverse_iterator(_M_start); }  reference operator[](size_type __n)    { return _M_start[difference_type(__n)]; }  const_reference operator[](size_type __n) const     { return _M_start[difference_type(__n)]; }
首先关注的第一个函数是_S_buffer_size(),它是对函数__deque_buf_size的简单封装。

static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }

其中__deque_buf_size的定义如下:

inline size_t __deque_buf_size(size_t __size) {  return __size < 512 ? size_t(512 / __size) : size_t(1);}
从上面可以看到,deque定义的缓冲区大小是512bytes,如果对象tp的大小大于512bytes,那么每个缓冲区的容量就只有一个tp,否则就是(512/sizeof(tp))个对象了。


deque的结构比较复杂,要理解deque设计细节,首先需要理解deque在内存组织上的特点,下面是deque组织结构示意图。


map是一个连续的内存空间,用于存储缓存空间的首地址,map的地址不够用的时候,就会重新申请map的空间,并且将原来存储的地址更新到新的位置。

在讨论deque实现细节之前,先从宏观上看一下如果希望实现上述的组织结构图,那么应该怎么做呢:

1.在尾部增加一个数据,如果数据空间够用,那么直接增加,finish->cur++就可以了;如果存储空间不够,需要申请新的内存,并且需要在map中注册,同时更新finish,指向新的缓存空间;如果此时map的存储空间不够用了,就应当申请新的map空间,将map的地址扩展过去,并且更新start和finish的node节点指针的值,按照这种思路,如果插入数据之后,那么原来的iterator会失效,因为iterator的node节点的值有可能会被修改,这样就没有办法跳转到下一个节点了。。。。好悲惨的说

2.如果在首部增加一个数据,如果存储空间够用,那么直接增加,start->cur--就可以了,如果存储空间不够用,就需要申请新的存储空间了,这个过程与在尾部增加一个数据差不多。

分析deque的内部实现细节,从deque的构造函数开始,deque的构造函数如下。

explicit deque(const allocator_type& __a = allocator_type())     : _Base(__a, 0) {}  deque(const deque& __x) : _Base(__x.get_allocator(), __x.size())     { uninitialized_copy(__x.begin(), __x.end(), _M_start); }  deque(size_type __n, const value_type& __value,        const allocator_type& __a = allocator_type()) : _Base(__a, __n)    { _M_fill_initialize(__value); }  explicit deque(size_type __n) : _Base(allocator_type(), __n)    { _M_fill_initialize(value_type()); }
可以看到,这个初始化里面都调用了函数_Base进行自开始的空间初始化。_Base的定义如下:

typedef _Deque_base<_Tp, _Alloc> _Base;
然后,看一下_Deque_base的定义,
template <class _Tp, class _Alloc>class _Deque_base {public:  typedef _Deque_iterator<_Tp,_Tp&,_Tp*>             iterator;  typedef _Deque_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;  typedef _Alloc allocator_type;  allocator_type get_allocator() const { return allocator_type(); }  _Deque_base(const allocator_type&, size_t __num_elements)    : _M_map(0), _M_map_size(0),  _M_start(), _M_finish() {    _M_initialize_map(__num_elements);//根据__num_elements进行初始化存储空间  }  _Deque_base(const allocator_type&)    : _M_map(0), _M_map_size(0),  _M_start(), _M_finish() {}  ~_Deque_base();    protected:  void _M_initialize_map(size_t);  void _M_create_nodes(_Tp** __nstart, _Tp** __nfinish);  void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish);  enum { _S_initial_map_size = 8 };protected:  _Tp** _M_map;  size_t _M_map_size;    iterator _M_start;  iterator _M_finish;  typedef simple_alloc<_Tp, _Alloc>  _Node_alloc_type;  typedef simple_alloc<_Tp*, _Alloc> _Map_alloc_type;  _Tp* _M_allocate_node()    { return _Node_alloc_type::allocate(__deque_buf_size(sizeof(_Tp))); }  void _M_deallocate_node(_Tp* __p)    { _Node_alloc_type::deallocate(__p, __deque_buf_size(sizeof(_Tp))); }  _Tp** _M_allocate_map(size_t __n)     { return _Map_alloc_type::allocate(__n); }  void _M_deallocate_map(_Tp** __p, size_t __n)     { _Map_alloc_type::deallocate(__p, __n); }};

从上面可以看到,deque在初始化的时候,会调用父类_Deque_base里面的构造函数_Deque_base(const allocator_type&, size_t __num_elements),这个函数最终调用的是 _M_initialize_map(__num_elements);。为了表述方便,M空间为存储map索引的空间,D空间为存储实际数据的缓存空间。该函数的原形如下:

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);//enum { _S_initial_map_size = 8 };,最小的map M空间是8个。  _M_map = _M_allocate_map(_M_map_size);//申请存放map的M空间  _Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2;  _Tp** __nfinish = __nstart + __num_nodes;      __STL_TRY {    _M_create_nodes(__nstart, __nfinish);//为start与finish之间的map分配对应的D空间。  }  __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));//最后一个节点中的cur指向的空间位置,应当是去掉整数deque_buf_size剩余的。}
可以看出来,deque在初始化的时候,D空间会比需求的多一个,至少会分配一个缓存D空间,以及至少8个存储map索引的M空间,如果需要的map节点大于8个,那么会分配的存储空间S+2个空间。上面的函数里面,调用函数 _M_allocate_map用于分配map索引的存储空间,该函数原型如下,直接调用alloc用来分配空间的。

typedef simple_alloc<_Tp*, _Alloc> _Map_alloc_type;_Tp** _M_allocate_map(size_t __n)     { return _Map_alloc_type::allocate(__n); }
此外,上面的函数里面,还调用了函数_M_create_nodes用于分配缓存D空间,该函数的原形如下:

template <class _Tp, class _Alloc>void _Deque_base<_Tp,_Alloc>::_M_create_nodes(_Tp** __nstart, _Tp** __nfinish)//传入的参数为[nstart,nfinish){  _Tp** __cur;  __STL_TRY {    for (__cur = __nstart; __cur < __nfinish; ++__cur)      *__cur = _M_allocate_node();//直接调用createnode函数//分配用于缓存的D空间  }  __STL_UNWIND(_M_destroy_nodes(__nstart, __cur));}

//调用alloc来分配存储空间typedef simple_alloc<_Tp, _Alloc>  _Node_alloc_type;_Tp* _M_allocate_node()    { return _Node_alloc_type::allocate(__deque_buf_size(sizeof(_Tp))); }
到这里,基本上deque的空间分配算是完结了,如果需要插入新的数据,当空间不足时,其实还是一样的会进行类似的数据分配。只不过需要修改map索引以及更新一些其他的标签。
要实现对于deque的访问,最离不开的是iterator,它是保障deque对外呈现单一连续空间的工程,iterator的部分定义如下:

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;//当前D空间中使用的地址  _Tp* _M_first;//标记当前D空间的起始地址  _Tp* _M_last;//标记当前D空间的完结地址  _Map_pointer _M_node;//标记map中的地址位  _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 */

从最上面的deque的结构组织图实现可以看出,iterator在实现的时候,利用cur、first、last以及node来实现map、以及缓存D空间之间的胶合的。

iterator最重要的就是++、--等操作了。逐一看一下这些函数的实现。

  reference operator*() const { return *_M_cur; }//返回iterator指向的缓存D空间的值#ifndef __SGI_STL_NO_ARROW_OPERATOR  pointer operator->() const { return _M_cur; }//返回iterator指向的缓存D空间的指针#endif /* __SGI_STL_NO_ARROW_OPERATOR */


判断两个iterator之间的距离:

difference_type operator-(const _Self& __x) const {    return difference_type(_S_buffer_size()) * (_M_node - __x._M_node - 1) +//-1是因为后面的计算多了1个buffer的距离      (_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;  }
_M_set_node函数定义如下;

  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());  }
++操作如果到达了结尾,那么直接调到下一个节点就可以了,然后重新设置一下各个标签。

--操作 的函数原型如下:

  _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;  }
由于first和last标记的空间是[frist,last),所以++和--的操作顺序是有所不同的。

+=操作使得iterator拥有了randomaccess的功能,其原型如下:

_Self& operator+=(difference_type __n)  {    difference_type __offset = __n + (_M_cur - _M_first);    if (__offset >= 0 && __offset < difference_type(_S_buffer_size()))//如果offset还在同一个节点范围内,直接加上就可以了      _M_cur += __n;    else {      difference_type __node_offset =        __offset > 0 ? __offset / difference_type(_S_buffer_size())//如果cur>0,那么需要进行偏移                   : -difference_type((-__offset - 1) / _S_buffer_size()) - 1;//如果<0 ,<span style="font-family: Arial, Helvetica, sans-serif;">从尾部开始数的话,</span><span style="font-family: Arial, Helvetica, sans-serif;">需要-1,</span>      _M_set_node(_M_node + __node_offset);      _M_cur = _M_first +         (__offset - __node_offset * difference_type(_S_buffer_size()));//计算出相应的node值    }    return *this;  }

剩下的iterator的操作就比较容易理解了,基本上都是对上面几个功能的略加封装。

_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());  }
至此,iterator的所有操作就结束了,看一下deque进行push_back、pop_back以及push_front和pop_front的操作是如何实现的。

void push_back(const value_type& __t) {    if (_M_finish._M_cur != _M_finish._M_last - 1) {//如果cur还没有到最后一个可用的空间,可以直接使用      construct(_M_finish._M_cur, __t);      ++_M_finish._M_cur;    }    else//已经到了最后一个可用空间,那么需要重新分配下一个空间了,因为finish.cur指向的是最后一个可用空间的下一个。      _M_push_back_aux(__t);  }
push_back如果空间不足的话,会调用_M_push_back_aux,其原型如下:

template <class _Tp, class _Alloc>void deque<_Tp,_Alloc>::_M_push_back_aux(const value_type& __t){  value_type __t_copy = __t;  _M_reserve_map_at_back();//调整指针的位置  *(_M_finish._M_node + 1) = _M_allocate_node();//申请新的空间  __STL_TRY {    construct(_M_finish._M_cur, __t_copy);//利用完最后一个空间    _M_finish._M_set_node(_M_finish._M_node + 1);//更新的参数    _M_finish._M_cur = _M_finish._M_first;//cur指向下一个可用的空间  }  __STL_UNWIND(_M_deallocate_node(*(_M_finish._M_node + 1)));}
_M_reserve_map_at_back()用于调整map的地址,原型如下:

 void _M_reserve_map_at_back (size_type __nodes_to_add = 1) {    if (__nodes_to_add + 1 > _M_map_size - (_M_finish._M_node - _M_map))//如果已经超出了当前的map可用空间了,需要重新分配      _M_reallocate_map(__nodes_to_add, false);  }
_M_reallocate_map函数主要是用来调整空间大小,首先需要申请一段空间,然后将原来的指针什么的都调整过去,再进行销毁,在这个过程中,应该只有finish和start的指针参数继续保持有效。

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) {//如果剩余空间够用,就直接调整一下start和finish区间的位置    __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 {//申请新的存储空间,然后将数据拷贝过去,并更新start和finish的值。    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);}

至此,push_back的所有操作基本都已经实现了。

push_front的实现:

 void push_front(const value_type& __t) {    if (_M_start._M_cur != _M_start._M_first) {//如果没有到做边界      construct(_M_start._M_cur - 1, __t);      --_M_start._M_cur;    }    else      _M_push_front_aux(__t);  }

_M_push_front_aux函数原型如下:

template <class _Tp, class _Alloc>void  deque<_Tp,_Alloc>::_M_push_front_aux(const value_type& __t){  value_type __t_copy = __t;  _M_reserve_map_at_front();//调整map的头部  *(_M_start._M_node - 1) = _M_allocate_node();//申请新的空间  __STL_TRY {    _M_start._M_set_node(_M_start._M_node - 1);//左移start    _M_start._M_cur = _M_start._M_last - 1;    construct(_M_start._M_cur, __t_copy);  }  __STL_UNWIND((++_M_start, _M_deallocate_node(*(_M_start._M_node - 1))));} 
_M_reserve_map_at_front函数原型如下:

 void _M_reserve_map_at_front (size_type __nodes_to_add = 1) {    if (__nodes_to_add > size_type(_M_start._M_node - _M_map))      _M_reallocate_map(__nodes_to_add, true);//增加map节点  }
这部分的操作和上面push_back的操作还是基本类似的。
push_back和push_front的操作到这里基本就完成了,这一对操作基本类似,在增加数据之前,需要判断是否有超过左右边界,[start,finish),以及[fist,last)的开闭需要比较注意。所以在具体的实现的时候,略有不同。

与push_back和push_front相对的是pop_back和pop_front,这两个函数如下,可以对比来看:

pop_back()

 void pop_back() {    if (_M_finish._M_cur != _M_finish._M_first) {      --_M_finish._M_cur;      destroy(_M_finish._M_cur);    }    else      _M_pop_back_aux();  }

pop_front()

void pop_front() {    if (_M_start._M_cur != _M_start._M_last - 1) {      destroy(_M_start._M_cur);      ++_M_start._M_cur;    }    else       _M_pop_front_aux();  }

这两个函数分别调用了_M_pop_back_aux和_M_pop_front_aux函数,其原型如下:

_M_pop_back_aux函数

void deque<_Tp,_Alloc>::_M_pop_back_aux(){  _M_deallocate_node(_M_finish._M_first);  _M_finish._M_set_node(_M_finish._M_node - 1);  _M_finish._M_cur = _M_finish._M_last - 1;  destroy(_M_finish._M_cur);}
_M_pop_front_aux函数
template <class _Tp, class _Alloc>void deque<_Tp,_Alloc>::_M_pop_front_aux(){  destroy(_M_start._M_cur);  _M_deallocate_node(_M_start._M_first);  _M_start._M_set_node(_M_start._M_node + 1);  _M_start._M_cur = _M_start._M_first;}      
这两个操作基本差不多,都是直接删除申请的存储空间,然后移动指针。


下面这个是clear()函数,用于清除整个deque。deque最初的状态是保留一个缓冲区,因此,clear之后恢复最初的状态,也是需要保留一个缓冲区的。 这里有一个疑问啊,如果一直使用pop_back或者pop_front是不是会导致空间全没有了,经过测试貌似还真是没有了额。。。这个待确认。。。

clear的函数原型如下:

template <class _Tp, class _Alloc> void deque<_Tp,_Alloc>::clear(){  for (_Map_pointer __node = _M_start._M_node + 1;//删除去头去尾的中间部分,这部分都是满的       __node < _M_finish._M_node;       ++__node) {    destroy(*__node, *__node + _S_buffer_size());//调用的destroy函数进行析构    _M_deallocate_node(*__node);//删除数据缓存节点  }  if (_M_start._M_node != _M_finish._M_node) {//如果还有两个节点    destroy(_M_start._M_cur, _M_start._M_last);//只进行析构。。    destroy(_M_finish._M_first, _M_finish._M_cur);    _M_deallocate_node(_M_finish._M_first);//只删除一个。  }  else    destroy(_M_start._M_cur, _M_finish._M_cur);  _M_finish = _M_start;//调整状态}

erase操作,清除[first,last)区间内的所有元素。

template <class _Tp, class _Alloc>typename deque<_Tp,_Alloc>::iterator deque<_Tp,_Alloc>::erase(iterator __first, iterator __last){  if (__first == _M_start && __last == _M_finish) {//如果需要清除的是整个区间,那么就直接调用clear()    clear();    return _M_finish;  }  else {    difference_type __n = __last - __first;//清除区间的长度,由于有iterator,可以很方便的就知道删除那些空间了。。    difference_type __elems_before = __first - _M_start;    if (__elems_before < difference_type((this->size() - __n) / 2)) {//清除数据的前方个数比较少      copy_backward(_M_start, __first, __last);      iterator __new_start = _M_start + __n;      destroy(_M_start, __new_start);      _M_destroy_nodes(__new_start._M_node, _M_start._M_node);      _M_start = __new_start;    }    else {      copy(__last, _M_finish, __first);      iterator __new_finish = _M_finish - __n;      destroy(__new_finish, _M_finish);      _M_destroy_nodes(__new_finish._M_node + 1, _M_finish._M_node + 1);      _M_finish = __new_finish;    }    return _M_start + __elems_before;  }}
最后一个函数insert,很不容易啊。。。 直接看最简单的版本的insert,其实都差不多的,为了适应不同的输入参数。

template <class _Tp, class _Alloc>void deque<_Tp, _Alloc>::insert(iterator __pos,                                const value_type* __first,                                const value_type* __last) {  size_type __n = __last - __first;//插入数据的个数  if (__pos._M_cur == _M_start._M_cur) {//在开头插入数据    iterator __new_start = _M_reserve_elements_at_front(__n);//调整之前数据空间    __STL_TRY {      uninitialized_copy(__first, __last, __new_start);//将数据拷贝过去,因为有iterator,所以拷贝的时候可以当做是连续存储空间      _M_start = __new_start;    }    __STL_UNWIND(_M_destroy_nodes(__new_start._M_node, _M_start._M_node));  }  else if (__pos._M_cur == _M_finish._M_cur) {//在末尾插入数据    iterator __new_finish = _M_reserve_elements_at_back(__n);//在增加数据空间    __STL_TRY {      uninitialized_copy(__first, __last, _M_finish);//拷贝过去      _M_finish = __new_finish;    }    __STL_UNWIND(_M_destroy_nodes(_M_finish._M_node + 1,                                   __new_finish._M_node + 1));  }  else    _M_insert_aux(__pos, __first, __last, __n);//调用标准函数}

_M_insert_aux函数原型如下:

template <class _Tp, class _Alloc>void deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos,                                      const value_type* __first,                                      const value_type* __last,                                      size_type __n){  const difference_type __elemsbefore = __pos - _M_start;//在pos之前的数据的个数  size_type __length = size();  if (__elemsbefore < __length / 2) {//如果前面的数据小于总的数据的一半,那么应该移动前面的数据    iterator __new_start = _M_reserve_elements_at_front(__n);//在前面增加n个缓存空间    iterator __old_start = _M_start;    __pos = _M_start + __elemsbefore;    __STL_TRY {      if (__elemsbefore >= difference_type(__n)) {        iterator __start_n = _M_start + difference_type(__n);        uninitialized_copy(_M_start, __start_n, __new_start);// -----|----A---|-----B---|------C----|三段数据,先将B移到A,然后将C移到B起点的位置,最后将        _M_start = __new_start;//新的数据移动到剩下的位置。        copy(__start_n, __pos, __old_start);        copy(__first, __last, __pos - difference_type(__n));      }      else {        const value_type* __mid =           __first + (difference_type(__n) - __elemsbefore);        __uninitialized_copy_copy(_M_start, __pos, __first, __mid,                                  __new_start);        _M_start = __new_start;        copy(__mid, __last, __old_start);      }    }    __STL_UNWIND(_M_destroy_nodes(__new_start._M_node, _M_start._M_node));  }  else {    iterator __new_finish = _M_reserve_elements_at_back(__n);    iterator __old_finish = _M_finish;    const difference_type __elemsafter =       difference_type(__length) - __elemsbefore;    __pos = _M_finish - __elemsafter;    __STL_TRY {      if (__elemsafter > difference_type(__n)) {        iterator __finish_n = _M_finish - difference_type(__n);        uninitialized_copy(__finish_n, _M_finish, _M_finish);        _M_finish = __new_finish;        copy_backward(__pos, __finish_n, __old_finish);        copy(__first, __last, __pos);      }      else {        const value_type* __mid = __first + __elemsafter;        __uninitialized_copy_copy(__mid, __last, __pos, _M_finish, _M_finish);        _M_finish = __new_finish;        copy(__first, __mid, __pos);      }    }    __STL_UNWIND(_M_destroy_nodes(_M_finish._M_node + 1,                                   __new_finish._M_node + 1));  }}

到此位置,deque的基本原理差不多就完成了,有很多函数可能存在很多不同的参数方案,略有不同,但是大的思路是一致的,一切都是为了优化性能而实现的。deque算是比较复杂的数据组织方式,后面的stack、queue默认的底层容器就是deque,所以后面的stack、queue就直接跳过了,至于堆排序什么的,后面复习排序算法的时候,再一起进行算法总结吧。



















0 0
原创粉丝点击