<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 */
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就直接跳过了,至于堆排序什么的,后面复习排序算法的时候,再一起进行算法总结吧。