STL源码分析 deque容器

源代码来自sgi-2.91版本stl_deque.h

deque总览图

(1)map相当于一个调度系统,引导你找到相应的buffer(默认为512字节)块,map此处表示映射的意思
(2)deque有头部和尾部两个iterator(start和finish),iterator里的node指向map映射表迭代器从而知道迭代器负责哪个区块,first指向相应buffer的头部,last指向相应buffer的尾部。
(3)两个iterator的cur有所不同:
start的cur始终指向buffer中最前面的元素,即保证cur指向的是整个deque最前的元素
finish的cur始终指向buffer中最后面的元素,即保证cur指向的是整个deque最后的元素
(4)前插元素找start迭代器,后插元素找finish迭代器,空间不足时对map映射指针表扩容。

重点:deque存储的数据其实是不连续的,分别在不同的buffer块,但通过iterator重载++,–运算符,实现对数据的随机访问,算法处理时就可以把deque容器看作是连续的。
在这里插入图片描述

iterator 迭代器定义


#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
template <class T, class Ref, class Ptr, size_t BufSiz>		//如果传入了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>   //如果没有传入BufSiz,则使用以下定义
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)); }		//返回缓冲区buffer大小
#endif

  typedef random_access_iterator_tag iterator_category;		//迭代器类型是连续的,通过Traits传递给算法
  typedef T value_type;
  typedef Ptr pointer;
  typedef Ref reference;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;		//数据间隔,通过Traits传递给算法
  //ptrdiff_t  long long unsigned int (64位操作系统)
  typedef T** map_pointer;

  typedef __deque_iterator self;	

  T* cur;			//指向当前数据地址
  T* first;			//指向缓冲区头部
  T* last;			//指向缓冲区尾部
  map_pointer node;		//

  __deque_iterator(T* x, map_pointer y) 	//传入map_pointer 的构造函数
    : 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) {}

  reference operator*() const { return *cur; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
//其他函数见下面分析
};

迭代器set_node函数

void set_node(map_pointer new_node) {		//重新设置此迭代器node指向的map映射表位置,此迭代器指向新的buffer块
    node = new_node;
    first = *new_node;
    last = first + difference_type(buffer_size());		//更新指针,暂不更新cur,各个函数单独处理
  }

迭代器operator- 重载

difference_type operator-(const self& x) const {	//两个迭代器相减,返回两个之间的相对位置,一般当前node是finish,x是start
    return difference_type(buffer_size()) * (node - x.node - 1) 	//找到两个之间的buffer有几块
    +
    (cur - first) + (x.last - x.cur);			//加上start和finish的数据
  }

self operator-(difference_type n) const {
    self tmp = *this;
    return tmp -= n;
  }

迭代器operator++ operator-- 重载

self& operator++() {		//前置++
    ++cur;			//后移指针
    if (cur == last) {			//超出buffer边界
      set_node(node + 1);		//此迭代器指向新的buffer块
      cur = first;
    }
    return *this; 
  }
  self operator++(int)  {		//后置++
    self tmp = *this;
    ++*this;			//调用前置++
    return tmp;	
  }

  self& operator--() {		//前置--
    if (cur == first) {
      set_node(node - 1);	//指向前面一块buffer块
      cur = last;
    }
    --cur;
    return *this;
  }
  self operator--(int) {	//后置--
    self tmp = *this;
    --*this;     //调用前置--
    return tmp;
  }

迭代器operator+= 重载

//非常精妙,甚至考虑到n为负数的情况
self& operator+=(difference_type n) {
    difference_type offset = n + (cur - first);
    if (offset >= 0 && offset < difference_type(buffer_size()))	//可以在同一块buffer内移动
      cur += n;
    else {
      difference_type node_offset =
        offset > 0 ? offset / difference_type(buffer_size())					//判断需要向后移动几个buffer块
                   : -difference_type((-offset - 1) / buffer_size()) - 1;		//负数处理,判断需要向前移动几个buffer块
      set_node(node + node_offset);			//新指向一块buffer块
      cur = first + (offset - node_offset * difference_type(buffer_size()));
    }
    return *this;
  }
  
	/*下面的运算符都是调用上面的+=*/
  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;
  }

迭代器operator[] 重载

reference operator[](difference_type n) const { return *(*this + n); }	//最终调用+=函数

迭代器operator* 重载

reference operator*() const { return *cur; }		//返回cur指向的数据,*start.cur就是最前数据,*finish.cur就是最后数据

deque类

template <class T, class Alloc = alloc, size_t BufSiz = 0> 		//默认alloc分配器,BufSiz代表缓冲区大小,默认为0实际设为1
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	//传入BufSiz版本
  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 */

#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;					//pointer*就是T**,map_pointer里存放的也是指针
  typedef simple_alloc<value_type, Alloc> data_allocator;		//simple_alloc是alloc的包装,实际上在调用alloc
  typedef simple_alloc<pointer, Alloc> map_allocator;

  static size_type buffer_size() {
    return __deque_buf_size(BufSiz, sizeof(value_type));	//设置缓冲区大小
  }
  static size_type initial_map_size() { return 8; }			//默认map_pointer放8个指针

protected:                      // Data members
  iterator start;				//指向map映射表的数据头部,start和finish从map映射表中间往两边扩容
  iterator finish;				//指向map映射表的数据尾部

  map_pointer map;				//map是map映射表实际的头部
  size_type map_size;			//初始化时8

__deque_buf_size函数

设置每个buffer分为多少块,与传入的数据类型有关,如果deque那么每个buffer块分为(512/4)128小块,详见图

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));
}

在这里插入图片描述

create_map_and_nodes函数

deque默认构造中调用此函数

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;		//计算需要的buffer块,num_elements<512的话就要1块

  map_size = max(initial_map_size(), num_nodes + 2);		//取大值,一般默认为8块buffer
  map = map_allocator::allocate(map_size);					//分配8个指针的内存空间

  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();		//原型见下面
      /*pointer allocate_node() { return data_allocator::allocate(buffer_size()); }*/	//分配512字节内存空间
  }
#     ifdef  __STL_USE_EXCEPTIONS 
  catch(...) {
    for (map_pointer n = nstart; n < cur; ++n)
      deallocate_node(*n);
    map_allocator::deallocate(map, map_size);
    throw;
  }
#     endif /* __STL_USE_EXCEPTIONS */
	/*初始化start和finish的指针信息*/
  start.set_node(nstart);	
  finish.set_node(nfinish);
  start.cur = start.first;
  finish.cur = finish.first + num_elements % buffer_size();
}

fill_initialize函数

deque构造函数中调用,传入参数版本

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);			//根据n分配内存空间
  map_pointer cur;
  __STL_TRY {
    for (cur = start.node; cur < finish.node; ++cur)		//初始化只有一块buffer则跳过for循环
      uninitialized_fill(*cur, *cur + buffer_size(), value);	//value值填充整个区间
    uninitialized_fill(finish.first, finish.cur, value);		//填充finish
  }
#       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 /* __STL_USE_EXCEPTIONS */
}

deque构造函数

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)	//容器初始化并填充n个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());   //分配空间并填充value_type默认构造
  }

deque析构函数

~deque() {
    destroy(start, finish);			//此处只是销毁了map映射表用到的指针
    destroy_map_and_nodes();		//回收所有内存
  }

// This is only used as a cleanup function in catch clauses.
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);		//回收整个map映射表
}

void deallocate_node(pointer n) {
    data_allocator::deallocate(n, buffer_size());		//回收每一块buffer块
  }

begin() end()

就是返回迭代器

iterator begin() { return start; }
  iterator end() { return finish; }
  const_iterator begin() const { return start; }
  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);
  }

deque operator[]重载

reference operator[](size_type n) { return start[difference_type(n)]; }		//实际返回start.cur,详见迭代器分析
  const_reference operator[](size_type n) const {
    return start[difference_type(n)];
  }

front() 、 back()函数

以下函数都用到了迭代器的重载

reference front() { return *start; }
  reference back() {
    iterator tmp = finish;
    --tmp;		//实际是cur--
    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; }

push_back函数

void push_back(const value_type& t) {
    if (finish.cur != finish.last - 1) {
      construct(finish.cur, t);			//如果finish那块空间还能放数据,那么直接在尾部构造t
      ++finish.cur;
    }
    else
      push_back_aux(t);		//否则需要新开一个buffer存放,注意此时实际上还有空间能在尾部构造t,但要提前准备好下一块buffer块
  }

// Called only if finish.cur == finish.last - 1.
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();		//map映射表数据尾部多加一个位置,判断是否需要扩容map
  *(finish.node + 1) = allocate_node();		//指向新的一块新分配的buffer
  __STL_TRY {
    construct(finish.cur, t_copy);			//在旧的那块buffer尾部构造t
    finish.set_node(finish.node + 1);		//更新finish.node
    finish.cur = finish.first;				//更新cur
  }
  __STL_UNWIND(deallocate_node(*(finish.node + 1)));
}

void reserve_map_at_back (size_type nodes_to_add = 1) {			
    if (nodes_to_add + 1 > map_size - (finish.node - map))		//map映射表需要扩容
      reallocate_map(nodes_to_add, false);
  }

pop_back函数

void pop_back() {
    if (finish.cur != finish.first) {		//cur还没到buffer头部
      --finish.cur;
      destroy(finish.cur);		//回收内存,调用析构函数
    }
    else
      pop_back_aux();		//finish.cur == finish.first调用,要pop前一块buffer的尾部元素
  }

// Called only if finish.cur == finish.first.
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>:: pop_back_aux() {
  deallocate_node(finish.first);		//回收旧的这块buffer
  finish.set_node(finish.node - 1);		//finish指向前面的一块buffer
  finish.cur = finish.last - 1;
  destroy(finish.cur);			//pop,调用析构函数
}

void deallocate_node(pointer n) {
    data_allocator::deallocate(n, buffer_size());		//回收buffer
  }

push_front函数

和push_back一样的分析思路

void push_front(const value_type& t) {
    if (start.cur != start.first) {
      construct(start.cur - 1, t);
      --start.cur;
    }
    else
      push_front_aux(t);	//新建buffer块push
  }
// Called only if start.cur == start.first.
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);
  }
void reserve_map_at_front (size_type nodes_to_add = 1) {
    if (nodes_to_add > start.node - map)
      reallocate_map(nodes_to_add, true);
  }
pointer allocate_node() { return data_allocator::allocate(buffer_size()); }

pop_front函数

原理同pop_back。

void pop_front() {
    if (start.cur != start.last - 1) {
      destroy(start.cur);
      ++start.cur;
    }
    else 
      pop_front_aux();
  }

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;
}  

void deallocate_node(pointer n) {
    data_allocator::deallocate(n, buffer_size());
  }

insert函数

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);		//有可能新建buffer,返回往前n个单位的新地址new_start 
    uninitialized_fill(new_start, start, x);		//迭代器的妙用,即使不在同一块buffer,因为重载了++,--算法可以当作它们连续
    start = new_start;
  }
  else if (pos.cur == finish.cur) {		//尾部插入数据
    iterator new_finish = reserve_elements_at_back(n);		//有可能新建buffer,返回往后n个单位的尾地址new_finish 
    uninitialized_fill(finish, new_finish, x);
    finish = new_finish;
  }
  else 
    insert_aux(pos, n, x);		//中间插入的话需要考虑更多情况
}

iterator reserve_elements_at_front(size_type n) {
    size_type vacancies = start.cur - start.first;			//计算在这块buffer中cur前面还可以存放多少元素
    if (n > vacancies) 					//空间不够的话需要新的buffer来放元素
      new_elements_at_front(n - vacancies);		//新建buffer来补数量
    return start - difference_type(n);			//实际更新start.cur的值
  }
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();		//计算需要多少块buffer来满足new_elements
  reserve_map_at_front(new_nodes);		//map映射表判断是否需要新node
  size_type i;
  __STL_TRY {
    for (i = 1; i <= new_nodes; ++i)
      *(start.node - i) = allocate_node();		//每一块新node分配空间buffer
  }
#       ifdef __STL_USE_EXCEPTIONS
  catch(...) {
    for (size_type j = 1; j < i; ++j)
      deallocate_node(*(start.node - j));      
    throw;
  }
#       endif /* __STL_USE_EXCEPTIONS */
}

insert_aux函数

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));
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值