前言
deque
容器比list
以及vector
容器都要复杂的多。它用两端都有开口的线性空间来存储数据,这样的话在首部操作数据的效率比vector
高,以及虽然它的迭代器是random_access_iterator_tag
型的,但是并不是原生指针,需要封装,比list
和vector
的迭代器都要复杂。它实现的机制是利用二级指针,维护一个指针数组map
,然后数组中存储的指针指向具体的线性空间。
map
并不是从开头依次使用,而是先选择二级指针数组中间的部分使用,这是为了deque
能够前后都加入等量的元素。我们把二级指针数组称为deque
的中控器,通过中控器得到真正存储元素的空间。
deque
的中控器
首先我们先简单介绍一下map
相关的知识,即定义部分,这样有利于我们后面对迭代器等知识的分析。
这里先列出部分源码:
//可以看到多了一个缺省参数BufSiz=0
//具体有什么作用,我们看到后面再说
template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque {
public: // Basic types
//一些常用类型的声明
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: // Iterators
//迭代器的声明
#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 /* __STL_NON_TYPE_TMPL_PARAM_BUG */
typedef __deque_iterator<T, T&, T*> iterator;
typedef __deque_iterator<T, const T&, const T*> const_iterator;
#endif /* __STL_NON_TYPE_TMPL_PARAM_BUG */
...
protected: // Internal typedefs
/* map_pointer的类型即T **
* 它先指向指针数组,指针数组里面的指针再指向存储元素的线性空间(即结点)
*/
typedef pointer* map_pointer;
/* 这里需要注意一下
* deque容器有两个空间配置器
* 一个用于配置元素
* 另一个用于配置指针数组
*/
typedef simple_alloc<value_type, Alloc> data_allocator;
typedef simple_alloc<pointer, Alloc> map_allocator;
使用这样的设计需要注意到几个问题。虽然每一个指针指向的空间是连续的,但是当一段数据横跨多个指针指向的连续空间时,就需要指针的切换了。如果要维持这种连续空间的假象,则需要考虑到每个线性空间跳到下一个线性空间的边界情况。
以及当指针数组不够大时需要再继续分配的情况。
为了支持这些操作,deque
的迭代器确实要复杂一些。下面我们就来看看deque
的迭代器源码。
deque
的迭代器
大概有100多行的样子,deque
的迭代器除了要取元素的值这些操作以外,还需要知道指针指向的一段线性空间的首尾,不然++
或者--
操作的时候,无法跳转到另外一段线性空间。
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 /* __STL_NON_TYPE_TMPL_PARAM_BUG */
template <class T, class Ref, class Ptr>
struct __deque_iterator {
typedef __deque_iterator<T, T&, T*> iterator;
typedef __deque_iterator<T,