STL之deque(三)

      deque除了维护一个先前说过的指向map的指标外,也维护start,finish两个迭代器,分别指向第一个缓冲区的第一个元素和最后缓冲区的最后一个元素(的下一位置)。此外它当然也必须记住目前的map大小。因为一旦map所提供的节点不足,就必须重新配置更大的一块map。

// deque的数据结构
template 
class deque
{
public:                         // Basic types
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type& reference;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;

public:                         // Iterators
	typedef __deque_iterator       iterator;

protected:                      // Internal typedefs

	typedef pointer* map_pointer;

	// 这个提供STL标准的allocator接口, 见
	typedef simple_alloc data_allocator;
	typedef simple_alloc map_allocator;

	// 获取缓冲区最大存储元素数量
	static size_type buffer_size()
	{
		return __deque_buf_size(BufSiz, sizeof(value_type));
	}

	static size_type initial_map_size() { return 8; }

protected:                      // Data members
	iterator start;               // 起始缓冲区
	iterator finish;              // 最后一个缓冲区

	// 指向map, map是一个连续的空间, 其每个元素都是一个指针,指向一个节点(缓冲区)
	map_pointer map;
	size_type map_size;   // map容量
	...
}

        有了上述结构,以下数个机能便可轻易完成:

iterator begin() { return start; }
	iterator end() { return finish; }

	// 提供随机访问能力, 其调用的是迭代器重载的operator []
	// 其实际地址需要进行一些列的计算, 效率有损失
	reference operator[](size_type n) { return start[difference_type(n)]; }

	reference front() { return *start; }
	reference back()
	{
		iterator tmp = finish;
		--tmp;
		return *tmp;
	}
        //没有直接调用finish-1是因为调用层次太深

	// 当前容器拥有的元素个数, 调用迭代器重载的operator -
	size_type size() const { return finish - start;; }
	size_type max_size() const { return size_type(-1); }

	// deque为空的时, 只有一个缓冲区
	bool empty() const { return finish == start; }
	typedef pointer* map_pointer;

	// 这个提供STL标准的allocator接口, 见
	typedef simple_alloc data_allocator;
	typedef simple_alloc map_allocator;

	// 获取缓冲区最大存储元素数量
	static size_type buffer_size()
	{
		return __deque_buf_size(BufSiz, sizeof(value_type));
	}

	static size_type initial_map_size() { return 8; }
deque(int n, const value_type& value)
		: start(), finish(), map(0), map_size(0)
{
	fill_initialize(n, value);
}

        deque::fill_initialize函数:

// 分配n个结点, 并以value为元素值初始化
template 
void deque::fill_initialize(size_type n,
    const value_type& value)
{
  create_map_and_nodes(n);  // 配置map和缓冲区
  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);
  }
  catch (...) {
    for (map_pointer n = start.node; n < cur; ++n)
      destroy(*n, *n + buffer_size());
    destroy_map_and_nodes();
    throw;
  }
}

       deque::create_map_and_nodes函数:

// 创建内部使用的map,并配置每一个缓冲区
template 
void deque::create_map_and_nodes(size_type num_elements)
{
    // 需要的结点数, 元素个数 / 每个缓冲区能容纳的元素数 + 1
  // 这里如果能整除,会多分配一个
  size_type num_nodes = num_elements / buffer_size() + 1;

  // map要维护的结点, 这里最小的值为8,最多为所需节点数+1,前后各留一个以便扩充
  map_size = max(initial_map_size(), num_nodes + 2);
  // 调用deque专属空间配置器,配置map空间
  map = map_allocator::allocate(map_size);

  // 将[nstart, nfinish)区间设置在map的中间,
  // 这样就能保证前后增长而尽可能减少map的重新分配次数
  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)
        // 为每一个map指针指向的缓冲区的每一个元素分配内存空间 
      *cur = allocate_node();
  }

  // 维护指针状态,为deque的两个迭代器start和finish赋初值
  start.set_node(nstart);
  finish.set_node(nfinish);
  start.cur = start.first;
  finish.cur = finish.first + num_elements % buffer_size();
}


你可能感兴趣的:(STL源码分析)