deque 源码分析 前言: deque
所提供的功能相较于其他顺序容器, 拥有较为强大的功能, 在实现上相对于 list
, vector
更复杂, deque
的迭代器是属于 random_access_iterator_tag
类型, 在分析 vector
时, 可以发现, 在某些极端情况下, 由于 vector
采用连续的空间储存元素, 会出现头插入以及扩容时进行大量元素的复制, 导致复杂度很高, 且对于空间的要求也是相对较高的. deque
则是 相对连续的 即它将多个数组按照顺序排序, 这样即使每个数组的头地址并不是连续的, 但是并不影响元素是连续 的, 这里的连续指的是逻辑上是连续, 而不是地址连续, deque
是一个双向开口的容器, 头尾插入和删除都是 O(1) 复杂度的, 空间也是可扩展的, 且扩展时不经常对已有的元素进行移动.
__deque_iterator迭代器结构 deque
的 iterator
和 vector
类似, 但是由于其结构为相对连续 所以对于 iterator
的设计要比 vector
的 iterator
更为复杂
全局函数 用来计算每一个数组的大小
1 2 3 4 inline size_t __deque_buf_size(size_t n, size_t sz){ return n != 0 ? n : (sz < 512 ? size_t (512 / sz) : size_t (1 )); }
类型定义 deque
的 iterator
是 random_access_iterator_tag
类型, 满足 traits
编程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #ifndef __STL_NON_TYPE_TMPL_PARAM_BUG template <class T , class Ref , class Ptr , size_t BufSiz >struct __deque_iterator { typedef __deque_iterator<T, T&, T*, BufSiz> iterator; typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator; static size_t buffer_size () {return __deque_buf_size(BufSiz, sizeof (T)); } #else template <class T , class Ref , class Ptr >struct __deque_iterator { typedef __deque_iterator<T, T&, T*> iterator; typedef __deque_iterator<T, const T&, const T*> const_iterator; static size_t buffer_size () {return __deque_buf_size(0 , sizeof (T)); } #endif typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef Ptr pointer; typedef Ref reference; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T** map_pointer; map_pointer node; typedef __deque_iterator self; ... };
满足 traits
编程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 template <class T , class Ref , class Ptr , size_t BufSiz >inline random_access_iterator_tagiterator_category (const __deque_iterator<T, Ref, Ptr, BufSiz>&) { return random_access_iterator_tag (); } template <class T , class Ref , class Ptr , size_t BufSiz >inline T* value_type (const __deque_iterator<T, Ref, Ptr, BufSiz>&) { return 0 ; } template <class T , class Ref , class Ptr , size_t BufSiz >inline ptrdiff_t * distance_type (const __deque_iterator<T, Ref, Ptr, BufSiz>&) { return 0 ; }
上文提到, 由于 deque
的连续性是使用数组进行拼接的, 所以需要一个指向指针的指针 来记录每块数组的地址, 所以 iterator
就需要一个指向指针的指针 来保证 iterator
在跨域数组的时候找到下(上)一顺序的数组
1 2 3 4 5 6 7 8 template <class T , class Ref , class Ptr , size_t BufSiz >struct __deque_iterator { ... typedef T** map_pointer; map_pointer node; ... };
同时还 iterator
中还设置了三个 T*
指针 cur
, first
, last
cur: 当前指向的位置
first: 该数组中头的位置
last: 该数组中尾的位置
1 2 3 4 5 6 7 8 9 template <class T , class Ref , class Ptr , size_t BufSiz >struct __deque_iterator { ... typedef T value_type; T* cur; T* first; T* last; ... };
构造函数 1 2 3 4 5 6 7 8 9 10 11 template <class T , class Ref , class Ptr , size_t BufSiz >struct __deque_iterator { ... __deque_iterator(T* x, map_pointer y) : cur (x), first (*y), last (*y + buffer_size ()), node (y) {} __deque_iterator() : cur (0 ), first (0 ), last (0 ), node (0 ) {} __deque_iterator(const iterator& x) : cur (x.cur), first (x.first), last (x.last), node (x.node) {} ... };
重载运算符 __deque_iterator
实现了基本运算符 在分析 __deque_iterator
的运算符之前先介绍一个基础函数 set_node
由于在 __deque_iterator
移动时可能会跨越数组, 所以需要重新设定指向数组指针的位置, set_node
则提供了更新指向将要前往的数组的头部位置的功能
1 2 3 4 5 6 7 8 9 10 11 12 template <class T , class Ref , class Ptr , size_t BufSiz >struct __deque_iterator { ... void set_node (map_pointer new_node) { node = new_node; first = *new_node; last = first + difference_type (buffer_size ()); } ... };
重载++和– 要注意 __deque_iterator
在向前或者向后移动在跨越数组时会出现越界的情况, 需要进行判断, 如果跨越了数组就要重新设置 node
指向的数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 template <class T , class Ref , class Ptr , size_t BufSiz >struct __deque_iterator { ... self& operator ++() { ++cur; if (cur == last) { set_node (node + 1 ); cur = first; } return *this ; } self& operator --() { if (cur == first) { set_node (node - 1 ); cur = last; } --cur; return *this ; } self operator ++(int ) { self tmp = *this ; ++*this ; return tmp; } self operator --(int ) { self tmp = *this ; --*this ; return tmp; } ... };
重载+, -等 由于 __deque_iterator
是 random_access_iterator_tag
类型迭代器, 所以支持 +, -
运算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 template <class T , class Ref , class Ptr , size_t BufSiz >struct __deque_iterator { ... reference operator *() const { return *cur; } reference operator [](difference_type n) const { return *(*this + n); } #ifndef __SGI_STL_NO_ARROW_OPERATOR pointer operator ->() const { return &(operator *()); } #endif self& operator +=(difference_type n) { difference_type offset = n + (cur - first); if (offset >= 0 && offset < difference_type (buffer_size ())) cur += n; else { difference_type node_offset = offset > 0 ? offset / difference_type (buffer_size ()) : -difference_type ((-offset - 1 ) / buffer_size ()) - 1 ; set_node (node + node_offset); cur = first + (offset - node_offset * difference_type (buffer_size ())); } return *this ; } difference_type operator -(const self& x) const { return difference_type (buffer_size ()) * (node - x.node - 1 ) + (cur - first) + (x.last - x.cur); } 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; } bool operator ==(const self& x) const { return cur == x.cur; } bool operator !=(const self& x) const { return !(*this == x); } bool operator <(const self& x) const { return (node == x.node) ? (cur < x.cur) : (node < x.node); } };
deque 结构 基本类型定义 deque
满足 traits
编程的嵌套定义类型.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { public : typedef T 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; public : #ifndef __STL_NON_TYPE_TMPL_PARAM_BUG typedef __deque_iterator<T, T&, T*, BufSiz> iterator; typedef __deque_iterator<T, const T&, const T&, BufSiz> const_iterator; #else typedef __deque_iterator<T, T&, T*> iterator; typedef __deque_iterator<T, const T&, const T*> const_iterator; #endif #ifdef __STL_CLASS_PARTIAL_SPECIALIZATION typedef reverse_iterator<const_iterator> const_reverse_iterator; typedef reverse_iterator<iterator> reverse_iterator; #else 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 protected : typedef pointer* map_pointer; typedef simple_alloc<value_type, Alloc> data_allocator; typedef simple_alloc<pointer, Alloc> map_allocator; ... };
map_pointer
是一个 指向指针的指针 用来管理 deque
中数组的数据
构造和析构函数 构造函数 有多种重载函数, 接受许多类型的创建 deque
的方式, 不过可以发现绝大部分的构造函数都会调用 create_map_and_nodes
这个方法, 其就是构造函数的核心, 在下面将会进行分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : deque () : start (), finish (), map (0 ), map_size (0 ) { create_map_and_nodes (0 ); } deque (const deque& x) : start (), finish (), map (0 ), map_size (0 ) { create_map_and_nodes (x.size ()); __STL_TRY { uninitialized_copy (x.begin (), x.end (), start); } __STL_UNWIND(destroy_map_and_nodes ()); } deque (size_type n, const value_type& value) : start (), finish (), map (0 ), map_size (0 ) { fill_initialize (n, value); } deque (int n, const value_type& value) : start (), finish (), map (0 ), map_size (0 ) { fill_initialize (n, value); } deque (long n, const value_type& value) : start (), finish (), map (0 ), map_size (0 ) { fill_initialize (n, value); } explicit deque (size_type n) : start(), finish(), map(0 ), map_size(0 ) { fill_initialize (n, value_type ()); } #ifdef __STL_MEMBER_TEMPLATES template <class InputIterator > deque (InputIterator first, InputIterator last) : start (), finish (), map (0 ), map_size (0 ) { range_initialize (first, last, iterator_category (first)); } #else deque (const value_type* first, const value_type* last) : start (), finish (), map (0 ), map_size (0 ) { create_map_and_nodes (last - first); __STL_TRY { uninitialized_copy (first, last, start); } __STL_UNWIND(destroy_map_and_nodes ()); } deque (const_iterator first, const_iterator last) : start (), finish (), map (0 ), map_size (0 ) { create_map_and_nodes (last - first); __STL_TRY { uninitialized_copy (first, last, start); } __STL_UNWIND(destroy_map_and_nodes ()); } #endif ... };
create_map_and_nodes 函数实现.
计算初始化时需要容纳多少元素
在默认开辟的空间和第一步中的空间取 max
保证 dqeue
在向前和向后扩展数组时都有空间
计算出初始时最前面数组和最后面数组的位置, 这里给两个位置前面预留的空间为 (map_size - num_nodes) / 2
保证了前后预留空间都相同
为已经确定的空间范围**(最前和最后两个数组之间)** 都分配一个 buffer_size
的数组
将 start
和 finish
中的 cur
指向所对应的数组, 并更新 first, lasr
, 即将 start
和 finish
指向第一个元素和最后一个元素的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::create_map_and_nodes (size_type num_elements) { size_type num_nodes = num_elements / buffer_size () + 1 ; map_size = max (initial_map_size (), num_nodes + 2 ); map = map_allocator::allocate (map_size); map_pointer nstart = map + (map_size - num_nodes) / 2 ; map_pointer nfinish = nstart + num_nodes - 1 ; map_pointer cur; __STL_TRY { for (cur = nstart; cur <= nfinish; ++cur) *cur = allocate_node (); } # ifdef __STL_USE_EXCEPTIONS catch (...) { for (map_pointer n = nstart; n < cur; ++n) deallocate_node (*n); map_allocator::deallocate (map, map_size); throw ; } # endif start.set_node (nstart); finish.set_node (nfinish); start.cur = start.first; finish.cur = finish.first + num_elements % buffer_size (); }
range_initialize 函数 虽然 deque
的 iterator
是 random_access_iterator_tag
类型, 但是在执行构造函数时可能接收到的是 list
或其他容器的迭代器, 就会通过该方法来确定如何向 deque
内部添加元素
这种设计考虑了不同迭代器的差异, 迭代器要 向下兼容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <class T , class Alloc , size_t BufSize >template <class InputIterator >void deque<T, Alloc, BufSize>::range_initialize (InputIterator first, InputIterator last, input_iterator_tag) { create_map_and_nodes (0 ); for ( ; first != last; ++first) push_back (*first); } template <class T , class Alloc , size_t BufSize >template <class ForwardIterator >void deque<T, Alloc, BufSize>::range_initialize (ForwardIterator first, ForwardIterator last, forward_iterator_tag) { size_type n = 0 ; distance (first, last, n); create_map_and_nodes (n); __STL_TRY { uninitialized_copy (first, last, start); } __STL_UNWIND(destroy_map_and_nodes ()); }
fill_initialize 函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::fill_initialize (size_type n, const value_type& value) { create_map_and_nodes (n); map_pointer cur; __STL_TRY { for (cur = start.node; cur < finish.node; ++cur) uninitialized_fill (*cur, *cur + buffer_size (), value); uninitialized_fill (finish.first, finish.cur, value); } #ifdef __STL_USE_EXCEPTIONS catch (...) { for (map_pointer n = start.node; n < cur; ++n) destroy (*n, *n + buffer_size ()); destroy_map_and_nodes (); throw ; } # endif }
析构函数, 分步释放内存.
释放开辟的各个数组内的元素
释放记录数组地址的数组空间
1 2 3 4 5 6 7 8 9 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : ~deque () { destroy (start, finish); destroy_map_and_nodes (); } };
deque
是一个”二维数组”并且每个数组之间并不连续, 所以需要一个数组一个数组的执行释放.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::destroy_map_and_nodes () { for (map_pointer cur = start.node; cur <= finish.node; ++cur) deallocate_node (*cur); map_allocator::deallocate (map, map_size); } template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : pointer allocate_node () { return data_allocator::allocate (buffer_size ()); } void deallocate_node (pointer n) { data_allocator::deallocate (n, buffer_size ()); } };
deque基本属性获取方法 deque
的 first
指向第一个元素的地址, finish
指向最后一个元素的后一个位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... protected : ... static size_type buffer_size () { return __deque_buf_size(BufSiz, sizeof (value_type)); } static size_type initial_map_size () { return 8 ; } protected : iterator start; iterator finish; map_pointer map; size_type map_size; public : iterator begin () { return start; } const_iterator begin () const { return start; } iterator end () { return finish; } const_iterator end () const { return finish; } reverse_iterator rbegin () { return reverse_iterator (finish); } reverse_iterator rend () { return reverse_iterator (start); } const_reverse_iterator rbegin () const { return const_reverse_iterator (finish); } const_reverse_iterator rend () const { return const_reverse_iterator (start); } reference front () { return *start; } reference back () { iterator tmp = finish; --tmp; return *tmp; } const_reference front () const { return *start; } const_reference back () const { const_iterator tmp = finish; --tmp; return *tmp; } size_type size () const { return finish - start;; } size_type max_size () const { return size_type (-1 ); } bool empty () const { return finish == start; } reference operator [](size_type n) { return start[difference_type (n)]; } const_reference operator [](size_type n) const { return start[difference_type (n)]; } ... };
deque 的操作符重载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : deque& operator = (const deque& x) { const size_type len = size (); if (&x != this ) { if (len >= x.size ()) erase (copy (x.begin (), x.end (), start), finish); else { const_iterator mid = x.begin () + difference_type (len); copy (x.begin (), mid, start); insert (finish, mid, x.end ()); } } return *this ; } #ifdef __STL_NON_TYPE_TMPL_PARAM_BUG public : bool operator ==(const deque<T, Alloc, 0 >& x) const { return size () == x.size () && equal (begin (), end (), x.begin ()); } bool operator !=(const deque<T, Alloc, 0 >& x) const { return size () != x.size () || !equal (begin (), end (), x.begin ()); } bool operator <(const deque<T, Alloc, 0 >& x) const { return lexicographical_compare (begin (), end (), x.begin (), x.end ()); } #endif ... }; template <class T , class Alloc , size_t BufSiz >bool operator ==(const deque<T, Alloc, BufSiz>& x, const deque<T, Alloc, BufSiz>& y) { return x.size () == y.size () && equal (x.begin (), x.end (), y.begin ()); } template <class T , class Alloc , size_t BufSiz >bool operator <(const deque<T, Alloc, BufSiz>& x, const deque<T, Alloc, BufSiz>& y) { return lexicographical_compare (x.begin (), x.end (), y.begin (), y.end ()); }
deque 的 元素操作 push, pop 由于 deque
都可以实现双向操作 所以其 push
, pop
的操作都类似于 list
的 push
和 pop
操作, 但是由于 list
采用链表实现, 所以不会涉及到容器边界的判断, 而由于 deque
是利用不连续的数组来实现元素的存储, 所以在插入和弹出数据是需要对边界线进行判断
push 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : void push_back (const value_type& t) { if (finish.cur != finish.last - 1 ) { construct (finish.cur, t); ++finish.cur; } else push_back_aux (t); } void push_front (const value_type& t) { if (start.cur != start.first) { construct (start.cur - 1 , t); --start.cur; } else push_front_aux (t); } ... };
如果在 push
操作中发现数组越界的情况, 就移动到相应的下一个数组进行 push
操作, 其是调用 push_front(back)_aux
方法来实现, 这个辅助方法会在后面进行介绍
push_front(back)_aux 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::push_back_aux (const value_type& t) { value_type t_copy = t; reserve_map_at_back (); *(finish.node + 1 ) = allocate_node (); __STL_TRY { construct (finish.cur, t_copy); finish.set_node (finish.node + 1 ); finish.cur = finish.first; } __STL_UNWIND(deallocate_node (*(finish.node + 1 ))); } template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::push_front_aux (const value_type& t) { value_type t_copy = t; reserve_map_at_front (); *(start.node - 1 ) = allocate_node (); __STL_TRY { start.set_node (start.node - 1 ); start.cur = start.last - 1 ; construct (start.cur, t_copy); } # ifdef __STL_USE_EXCEPTIONS catch (...) { start.set_node (start.node + 1 ); start.cur = start.first; deallocate_node (*(start.node - 1 )); throw ; } # endif }
这里要注意, 由于在尾部插入的时候, 是判断的插入的位置是不是该数组的最后一个位置, 也即 finish
是指向的最后一个元素的后一个地址, 而 first
当前指向的位置是有元素的, 所以 push_back
是先执行构造再移动 node
, push_front
则是先移动 node
再进行构造, 下面 pop
也是同理
pop 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : void pop_back () { if (finish.cur != finish.first) { --finish.cur; destroy (finish.cur); } else pop_back_aux (); } void pop_front () { if (start.cur != start.last - 1 ) { destroy (start.cur); ++start.cur; } else pop_front_aux (); } ... };
pop判断越界后执行 pop_xxx_aux
方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>:: pop_back_aux () { deallocate_node (finish.first); finish.set_node (finish.node - 1 ); finish.cur = finish.last - 1 ; destroy (finish.cur); } template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::pop_front_aux () { destroy (start.cur); deallocate_node (start.first); start.set_node (start.node + 1 ); start.cur = start.first; }
注意 这里 dellocate_node
函数是析构的数组空间
reserve_map_at一类函数. pop和push都先调用了reserve_map_at_XX函数, 这些函数 主要是为了判断前后空间是否足够.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : void new_elements_at_front (size_type new_elements); void new_elements_at_back (size_type new_elements) ; void destroy_nodes_at_front (iterator before_start) ; void destroy_nodes_at_back (iterator after_finish) ; protected : void reserve_map_at_back (size_type nodes_to_add = 1 ) { if (nodes_to_add + 1 > map_size - (finish.node - map)) reallocate_map (nodes_to_add, false ); } void reserve_map_at_front (size_type nodes_to_add = 1 ) { if (nodes_to_add > start.node - map) reallocate_map (nodes_to_add, true ); } void reallocate_map (size_type nodes_to_add, bool add_at_front) ; ... };
对于 reallocate_map 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::reallocate_map (size_type nodes_to_add, bool add_at_front) { size_type old_num_nodes = finish.node - start.node + 1 ; size_type new_num_nodes = old_num_nodes + nodes_to_add; map_pointer new_nstart; if (map_size > 2 * new_num_nodes) { new_nstart = map + (map_size - new_num_nodes) / 2 + (add_at_front ? nodes_to_add : 0 ); if (new_nstart < start.node) copy (start.node, finish.node + 1 , new_nstart); else copy_backward (start.node, finish.node + 1 , new_nstart + old_num_nodes); } else { size_type new_map_size = map_size + max (map_size, nodes_to_add) + 2 ; map_pointer new_map = map_allocator::allocate (new_map_size); new_nstart = new_map + (new_map_size - new_num_nodes) / 2 + (add_at_front ? nodes_to_add : 0 ); copy (start.node, finish.node + 1 , new_nstart); map_allocator::deallocate (map, map_size); map = new_map; map_size = new_map_size; } start.set_node (new_nstart); finish.set_node (new_nstart + old_num_nodes - 1 ); }
其是在 deque
空间不足时使用, 来进行扩容
deque 的空间足够使用 其内部移动 start
, finish
来实现, 这种情况一般是前后剩余空间失衡所进行的移动
deque 空间不足 i. 申请更大的空间 ii. 将所有元素拷贝到新的空间 iii. 修改原 map 的 start 和 finish 指向
1 2 3 4 5 6 7 8 9 10 11 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::destroy_nodes_at_front (iterator before_start) { for (map_pointer n = before_start.node; n < start.node; ++n) deallocate_node (*n); } template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::destroy_nodes_at_back (iterator after_finish) { for (map_pointer n = after_finish.node; n > finish.node; --n) deallocate_node (*n); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : iterator reserve_elements_at_front (size_type n) { size_type vacancies = start.cur - start.first; if (n > vacancies) new_elements_at_front (n - vacancies); return start - difference_type (n); } iterator reserve_elements_at_back (size_type n) { size_type vacancies = (finish.last - finish.cur) - 1 ; if (n > vacancies) new_elements_at_back (n - vacancies); return finish + difference_type (n); } ... }; template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::new_elements_at_front (size_type new_elements) { size_type new_nodes = (new_elements + buffer_size () - 1 ) / buffer_size (); reserve_map_at_front (new_nodes); size_type i; __STL_TRY { for (i = 1 ; i <= new_nodes; ++i) *(start.node - i) = allocate_node (); } # ifdef __STL_USE_EXCEPTIONS catch (...) { for (size_type j = 1 ; j < i; ++j) deallocate_node (*(start.node - j)); throw ; } #endif } template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::new_elements_at_back (size_type new_elements) { size_type new_nodes = (new_elements + buffer_size () - 1 ) / buffer_size (); reserve_map_at_back (new_nodes); size_type i; __STL_TRY { for (i = 1 ; i <= new_nodes; ++i) *(finish.node + i) = allocate_node (); } #ifdef __STL_USE_EXCEPTIONS catch (...) { for (size_type j = 1 ; j < i; ++j) deallocate_node (*(finish.node + j)); throw ; } #endif }
删除操作 之前考虑到 deque
在前后实现插入时为了保证时间复杂度为 O(1), 所以在前后预留了空间, 所以 push
和 `pop 都可以在前面的数组进行操作
对于 earse
由于 deque
是由数组构成的, 所以地址空间是 相对连续 的, 故在删除时也要像 vector
一样, 要移动大量元素, deque
为了保证效率尽可能的高, 采用了判断删除的位置是中间偏后还是中间偏前来进行移动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : iterator erase (iterator pos) { iterator next = pos; ++next; difference_type index = pos - start; if (index < (size () >> 1 )) { copy_backward (start, pos, next); pop_front (); } else { copy (next, finish, pos); pop_back (); } return start + index; } iterator erase (iterator first, iterator last) ; void clear () ; ... };
erase(iterator first, iterator last)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 template <class T , class Alloc , size_t BufSize >deque<T, Alloc, BufSize>::iterator deque<T, Alloc, BufSize>::erase (iterator first, iterator last) { if (first == start && last == finish) { clear (); return finish; } else { difference_type n = last - first; difference_type elems_before = first - start; if (elems_before < (size () - n) / 2 ) { copy_backward (start, first, last); iterator new_start = start + n; destroy (start, new_start); for (map_pointer cur = start.node; cur < new_start.node; ++cur) data_allocator::deallocate (*cur, buffer_size ()); start = new_start; } else { copy (last, finish, first); iterator new_finish = finish - n; destroy (new_finish, finish); for (map_pointer cur = new_finish.node + 1 ; cur <= finish.node; ++cur) data_allocator::deallocate (*cur, buffer_size ()); finish = new_finish; } return start + elems_before; } }
clear 方法 删除所有元素, 一共有两步
从第二个数组一直到倒数第二个数组, 一次性全部删除, 因为中间的数组一定是满的
删除首尾两个数组元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::clear () { for (map_pointer node = start.node + 1 ; node < finish.node; ++node) { destroy (*node, *node + buffer_size ()); data_allocator::deallocate (*node, buffer_size ()); } if (start.node != finish.node) { destroy (start.cur, start.last); destroy (finish.first, finish.cur); data_allocator::deallocate (finish.first, buffer_size ()); } else destroy (start.cur, finish.cur); finish = start; }
swap deque
的swap操作也只是交换了start, finish, map, 并没有交换所有的元素.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... void swap (deque& x) { __STD::swap (start, x.start); __STD::swap (finish, x.finish); __STD::swap (map, x.map); __STD::swap (map_size, x.map_size); } ... }; template <class T , class Alloc , size_t BufSiz >inline void swap (deque<T, Alloc, BufSiz>& x, deque<T, Alloc, BufSiz>& y) { x.swap (y); }
resize函数 resize函数 . 重新将deque
进行调整, 实现与list
一样的.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : void resize (size_type new_size) { resize (new_size, value_type ()); } void resize (size_type new_size, const value_type& x) { const size_type len = size (); if (new_size < len) erase (start + new_size, finish); else insert (finish, new_size - len, x); } };
insert insert 实现 先列出所有的重载方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 iterator insert (iterator position, const value_type& x) ;iterator insert (iterator position) ;void insert (iterator pos, size_type n, const value_type& x) ;void insert (iterator pos, int n, const value_type& x) ;void insert (iterator pos, long n, const value_type& x) ;void insert (iterator pos, InputIterator first, InputIterator last) ;void insert (iterator pos, const value_type* first, const value_type* last) ;void insert (iterator pos, const_iterator first, const_iterator last) ;void insert (iterator pos, InputIterator first, InputIterator last, input_iterator_tag) ;void insert (iterator pos, ForwardIterator first, ForwardIterator last,forward_iterator_tag) ;
单点插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template <class T , class Alloc = alloc, size_t BufSiz = 0 > class deque { ... public : iterator insert (iterator position, const value_type& x) { if (position.cur == start.cur) { push_front (x); return start; } else if (position.cur == finish.cur) { push_back (x); iterator tmp = finish; --tmp; return tmp; } else { return insert_aux (position, x); } } };
单位置插入多个元素
**insert(iterator pos, size_type n, const value_type& x) ** 在指定的位置插入n个元素并初始化.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::insert (iterator pos, size_type n, const value_type& x) { if (pos.cur == start.cur) { iterator new_start = reserve_elements_at_front (n); uninitialized_fill (new_start, start, x); start = new_start; } else if (pos.cur == finish.cur) { iterator new_finish = reserve_elements_at_back (n); uninitialized_fill (finish, new_finish, x); finish = new_finish; } else insert_aux (pos, n, x); } void insert (iterator pos, int n, const value_type& x) { insert (pos, (size_type) n, x); } void insert (iterator pos, long n, const value_type& x) { insert (pos, (size_type) n, x); }
**void insert(iterator pos, InputIterator first, InputIterator last) **. 通过参数的类型选择最优, 高效率的插入方式.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 template <class InputIterator >void insert (iterator pos, InputIterator first, InputIterator last) { insert (pos, first, last, iterator_category (first)); } template <class T , class Alloc , size_t BufSize >template <class InputIterator >void deque<T, Alloc, BufSize>::insert (iterator pos,InputIterator first, InputIterator last,input_iterator_tag) { copy (first, last, inserter (*this , pos)); } template <class T , class Alloc , size_t BufSize >template <class ForwardIterator >void deque<T, Alloc, BufSize>::insert (iterator pos,ForwardIterator first,ForwardIterator last,forward_iterator_tag) { size_type n = 0 ; distance (first, last, n); if (pos.cur == start.cur) { iterator new_start = reserve_elements_at_front (n); __STL_TRY { uninitialized_copy (first, last, new_start); start = new_start; } __STL_UNWIND(destroy_nodes_at_front (new_start)); } else if (pos.cur == finish.cur) { iterator new_finish = reserve_elements_at_back (n); __STL_TRY { uninitialized_copy (first, last, finish); finish = new_finish; } __STL_UNWIND(destroy_nodes_at_back (new_finish)); } else insert_aux (pos, first, last, n); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::insert (iterator pos,const value_type* first,const value_type* last) { size_type n = last - first; if (pos.cur == start.cur) { iterator new_start = reserve_elements_at_front (n); __STL_TRY { uninitialized_copy (first, last, new_start); start = new_start; } __STL_UNWIND(destroy_nodes_at_front (new_start)); } else if (pos.cur == finish.cur) { iterator new_finish = reserve_elements_at_back (n); __STL_TRY { uninitialized_copy (first, last, finish); finish = new_finish; } __STL_UNWIND(destroy_nodes_at_back (new_finish)); } else insert_aux (pos, first, last, n); } template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::insert (iterator pos,const_iterator first,const_iterator last){ size_type n = last - first; if (pos.cur == start.cur) { iterator new_start = reserve_elements_at_front (n); __STL_TRY { uninitialized_copy (first, last, new_start); start = new_start; } __STL_UNWIND(destroy_nodes_at_front (new_start)); } else if (pos.cur == finish.cur) { iterator new_finish = reserve_elements_at_back (n); __STL_TRY { uninitialized_copy (first, last, finish); finish = new_finish; } __STL_UNWIND(destroy_nodes_at_back (new_finish)); } else insert_aux (pos, first, last, n); }
insert_aux
上面的每一个方法, 基本都调用了 insert_aux
方法, 下面就介绍一下该方法
**insert_aux(iterator pos, const value_type& x) **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 template <class T , class Alloc , size_t BufSize >typename deque<T, Alloc, BufSize>::iteratordeque<T, Alloc, BufSize>::insert_aux (iterator pos, const value_type& x) { difference_type index = pos - start; value_type x_copy = x; if (index < size () / 2 ) { push_front (front ()); iterator front1 = start; ++front1; iterator front2 = front1; ++front2; pos = start + index; iterator pos1 = pos; ++pos1; copy (front2, pos1, front1); } else { push_back (back ()); iterator back1 = finish; --back1; iterator back2 = back1; --back2; pos = start + index; copy_backward (pos, back2, back1); } *pos = x_copy; return pos; }
**insert_aux(iterator pos, size_type n, const value_type& x) **
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::insert_aux (iterator pos, size_type n, const value_type& x) { const difference_type elems_before = pos - start; size_type length = size (); value_type x_copy = x; if (elems_before < length / 2 ) { iterator new_start = reserve_elements_at_front (n); iterator old_start = start; pos = start + elems_before; __STL_TRY { if (elems_before >= difference_type (n)) { iterator start_n = start + difference_type (n); uninitialized_copy (start, start_n, new_start); start = new_start; copy (start_n, pos, old_start); fill (pos - difference_type (n), pos, x_copy); } else { __uninitialized_copy_fill(start, pos, new_start, start, x_copy); start = new_start; fill (old_start, pos, x_copy); } } __STL_UNWIND(destroy_nodes_at_front (new_start)); } else { iterator new_finish = reserve_elements_at_back (n); iterator old_finish = finish; const difference_type elems_after = difference_type (length) - elems_before; pos = finish - elems_after; __STL_TRY { if (elems_after > difference_type (n)) { iterator finish_n = finish - difference_type (n); uninitialized_copy (finish_n, finish, finish); finish = new_finish; copy_backward (pos, finish_n, old_finish); fill (pos, pos + difference_type (n), x_copy); } else { __uninitialized_fill_copy(finish, pos + difference_type (n), x_copy, pos, finish); finish = new_finish; fill (pos, old_finish, x_copy); } } __STL_UNWIND(destroy_nodes_at_back (new_finish)); } }
剩余方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 #ifdef __STL_MEMBER_TEMPLATES template <class T , class Alloc , size_t BufSize >template <class ForwardIterator >void deque<T, Alloc, BufSize>::insert_aux (iterator pos, ForwardIterator first, ForwardIterator last, size_type n) { const difference_type elems_before = pos - start; size_type length = size (); if (elems_before < length / 2 ) { iterator new_start = reserve_elements_at_front (n); iterator old_start = start; pos = start + elems_before; __STL_TRY { if (elems_before >= difference_type (n)) { iterator start_n = start + difference_type (n); uninitialized_copy (start, start_n, new_start); start = new_start; copy (start_n, pos, old_start); copy (first, last, pos - difference_type (n)); } else { ForwardIterator mid = first; advance (mid, difference_type (n) - elems_before); __uninitialized_copy_copy(start, pos, first, mid, new_start); start = new_start; copy (mid, last, old_start); } } __STL_UNWIND(destroy_nodes_at_front (new_start)); } else { iterator new_finish = reserve_elements_at_back (n); iterator old_finish = finish; const difference_type elems_after = difference_type (length) - elems_before; pos = finish - elems_after; __STL_TRY { if (elems_after > difference_type (n)) { iterator finish_n = finish - difference_type (n); uninitialized_copy (finish_n, finish, finish); finish = new_finish; copy_backward (pos, finish_n, old_finish); copy (first, last, pos); } else { ForwardIterator mid = first; advance (mid, elems_after); __uninitialized_copy_copy(mid, last, pos, finish, finish); finish = new_finish; copy (first, mid, pos); } } __STL_UNWIND(destroy_nodes_at_back (new_finish)); } } #else template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::insert_aux (iterator pos, const value_type* first, const value_type* last, size_type n) { const difference_type elems_before = pos - start; size_type length = size (); if (elems_before < length / 2 ) { iterator new_start = reserve_elements_at_front (n); iterator old_start = start; pos = start + elems_before; __STL_TRY { if (elems_before >= difference_type (n)) { iterator start_n = start + difference_type (n); uninitialized_copy (start, start_n, new_start); 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) - elems_before); __uninitialized_copy_copy(start, pos, first, mid, new_start); start = new_start; copy (mid, last, old_start); } } __STL_UNWIND(destroy_nodes_at_front (new_start)); } else { iterator new_finish = reserve_elements_at_back (n); iterator old_finish = finish; const difference_type elems_after = difference_type (length) - elems_before; pos = finish - elems_after; __STL_TRY { if (elems_after > difference_type (n)) { iterator finish_n = finish - difference_type (n); uninitialized_copy (finish_n, finish, finish); finish = new_finish; copy_backward (pos, finish_n, old_finish); copy (first, last, pos); } else { const value_type* mid = first + elems_after; __uninitialized_copy_copy(mid, last, pos, finish, finish); finish = new_finish; copy (first, mid, pos); } } __STL_UNWIND(destroy_nodes_at_back (new_finish)); } } template <class T , class Alloc , size_t BufSize >void deque<T, Alloc, BufSize>::insert_aux (iterator pos, const_iterator first, const_iterator last, size_type n) { const difference_type elems_before = pos - start; size_type length = size (); if (elems_before < length / 2 ) { iterator new_start = reserve_elements_at_front (n); iterator old_start = start; pos = start + elems_before; __STL_TRY { if (elems_before >= n) { iterator start_n = start + n; uninitialized_copy (start, start_n, new_start); start = new_start; copy (start_n, pos, old_start); copy (first, last, pos - difference_type (n)); } else { const_iterator mid = first + (n - elems_before); __uninitialized_copy_copy(start, pos, first, mid, new_start); start = new_start; copy (mid, last, old_start); } } __STL_UNWIND(destroy_nodes_at_front (new_start)); } else { iterator new_finish = reserve_elements_at_back (n); iterator old_finish = finish; const difference_type elems_after = length - elems_before; pos = finish - elems_after; __STL_TRY { if (elems_after > n) { iterator finish_n = finish - difference_type (n); uninitialized_copy (finish_n, finish, finish); finish = new_finish; copy_backward (pos, finish_n, old_finish); copy (first, last, pos); } else { const_iterator mid = first + elems_after; __uninitialized_copy_copy(mid, last, pos, finish, finish); finish = new_finish; copy (first, mid, pos); } } __STL_UNWIND(destroy_nodes_at_back (new_finish)); } }
总结: 为了渐少在增加或者删除元素时移动元素所带来的时间复杂度的提升, deque
的设计不可谓不复杂, 但是我认为, 其是为了支持更多的功能而采用如此复杂的设计. 不过其中一些操作在我看来是不需要进行深入了解的, 比如 earse
以及 insert
操作, 其原因在于对于 deque
的定义双端队列 的元素出入顺序就只允许首尾进出 , 所以对于deque
设计出的随机插入, 删除, 提取元素是不符合双端队列的定义, 而且绝大多数使用者都是按照双端队列的定义来进行使用的, 我暂时没有思考出 deque
提供如此复杂的设计和功能是出于什么目的, 不过以后在阅读了更多的优秀源码之后, 可能会得到答案, 到时会进行分析==(预定 <分析为何部分 **STL** 容器的设计复杂度远超过其定义> )==.
在后续实现自己 Tiny STL 时, 考虑使用 list
作为适配器来实现 deque
的功能, 其实对于 stack
和 queue
使用list
来实现底层容器在时间复杂度上是相对优于标准库提供的deque
, 对于绝大多数使用者, 本质上还是在使用其定义出的结构来使用此类容器, 所以并不会设计的如此复杂, 从而考虑尽可能降低时间复杂度