00 写在前面
【STL源码剖析】总结笔记(6):iterator的设计与神奇的traits
在掌握了迭代器的基本设计原理之后,我们就可以来看剩下的序列式容器的实现了。这时我们可以把注意力更多地集中在每一个容器本身的设计上。
01 概述
deque是一种双向开口的连续线性空间,也就是可以在头尾两端进行插入和删除操作。我们知道vector是单向开口的连续线性空间,在空间不足的时候需要另寻更大的空间并进行移植。
为什么说deque巧妙呢,因为deque没有容量的概念,可以动态地增加空间。
但是这种连续其实只是deque营造的一种“假象”,我们先来看一下deque是如何实现连续的。
先不去看iterator,只看中间部分。
可以发现map的地方控制着很多的指针,而每个指针都指向一块buffer。
在添加元素时,只需要在buffer中添加即可。如果到达边界,那么就再扩充map中维护的指针即可。这也就是为什么deque可以左右扩充的原因。
但这也意味着想要维持连续的“假象”,iterator将会做出巨大的改变(重载)来实现比如++,–的操作。
后面我们来一一说明。
02 deque的结构
从上图中我们简单的了解了一下deque的结构。
这里的map其实就是deque的控制中心(注意这个map不是STL中的map)。map是一小块连续的空间(底层其实就是vector),其中的每一个node指向一大段连续空间buffer,在STL中可以指定其大小。
直接来看实现:
template <class T,class Alloc=alloc,size_t BufSize=0>
class deque{
public:
typedef T value_type;
typedef _deque_iterator<T,T&,T*,BufSiz>iterator;
protected:
typedef pointer* map_pointer;
protected:
iterator start;
iterator finish;
map_pointer map;//1
size_type map_size;//2
}
对照上图来看这段代码
-
首先关注map,map是指向控制中心这段空间的指针,而这其中又包含着指针,所以map的类型是指针的指针。(T**)
-
map_size就是map的大小,比如上图中就是8。
-
我们可以思考一下deque的大小是多少字节。
map是指针结构:4字节。map_size 4字节。还需要知道iterator的大小。
而在iterator里有上图中的表示的四个部分:cur,first,last,node。一共是16字节。
所以deque的大小是16+16+4+4=40字节
03 deque的迭代器
接下来我们可以仔细研究一下deque的迭代器了,这也是deque的灵魂。因为deque内部本身缓冲区的分割开的,如果想要使其连续,iterator必须可以精确地找到上一个或者下一个buffer的位置,要做一些特殊情况的判断。