一、deque的中控器
deque是连续空间(至少逻辑上看来如此),连续线性空间总令我们联想到array或vector。array无法成长,vector虽可成长,却只能向尾端成长,而且其所谓的成长原是个假象,事实上是(1)另觅更大空间;(2)将原数据复制过去;(3)释放原空间三部曲。如果不是vector每次配置新空间时都有留下一些余裕,其成长假象所带来的代价将是相当高昂。
deque系由一段一段的定量连续空间构成。一旦有必要在deque的前端或尾端增加新空间,便配置一段定量连续空间,串接在整个deque的头端或尾端。deque的最大任务,便是在这些分段的定量连续空间上,维护其整体连续的假象,并提供随机存取的借口。避开了“重新配置、复制、释放”的轮回,代价则是复杂的迭代器架构。
受到分段连续线性空间的字面影响,我们可能以为deque的实现复杂度和vector相比虽不中亦不远矣,其实不然。主要因为,既是分段连续线性空间,就必须有中央控制,而为了维持整体连续的假象,数据结构的设计及迭代器前进后退等操作都颇为繁琐。deque的实现代码分量远比vector或list都多得多。
deque采用一块所谓的map(注意,不是STL的map容器)作为主控。这里所谓map是一小块连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。SGI STL 允许我们指定缓冲区大小,默认值0表示将使用512 bytes 缓冲区。
二、deque的迭代器
让我们思考一下,deque的迭代器应该具备什么结构,首先,它必须能够指出分段连续空间(亦即缓冲区)在哪里,其次它必须能够判断自己是否已经处于其所在缓冲区的边缘,如果是,一旦前进或后退就必须跳跃至下一个或上一个缓冲区。为了能够正确跳跃,deque必须随时掌握管控中心(map)。所以在迭代器中需要定义:当前元素的指针,当前元素所在缓冲区的起始指针,当前元素所在缓冲区的尾指针,指向map中指向所在缓区地址的指针。
在进行迭代器的移动时,需要考虑跨缓冲区的情况。
重载前加(减),在实现后加(减)时,调用重载的前加(减)。
重载+=,实现+时,直接调用+=,实现-=时,调用+=负数,实现-时,调用-=.
//当需要实现新的功能时,最好使用已经重载好的操作,即方便有安全。。。。
另外,deque在效率上来说是不够vector好的,因此有时候在对deque进行sort的时候,需要先将元素移到vector再进行sort,然后移回来。
构造函数:根据缓冲区设置大小和元素个数,决定map的大小;给map分配空间,根据缓冲区的个数,分配缓冲区,默认指定一个缓冲区;
设置start和finish迭代器,满足左闭右开的原则。
push_back:如果空间满足,直接插入;不满足,调用push_back_aux。
push_back_aux:先调用reverse_map_at_back,若符合某种条件,重换一个map;分配空间。
reserve_map_at_back:看看map有没有满,满的话,调用reallocate_map。
reallocate_map:如果前端或后端pop过多,就会导致大量的空闲空间,如果是这种情况,则不用新分配空间,调整一下start的位置即可;
如果不够,则需要重新申请空间。
pop:析构元素,如果是最后一块还需要删除空间。
erase:需要判断,前面的元素少还是后面的元素少,移动较少的部分。
insert:判断位置,如果为前端或后端直接调用push操作,否则,移动较少的一端。
deque的构造与内存管理:
由于deque的设计思想就是由一块块的缓存区连接起来的,因此它的内存管理会比较复杂。插入的时候要考虑是否要跳转缓存区、是否要新建map节点(和vector一样,其实是重新分配一块空间给map,删除原来空间)、插入后元素是前面元素向前移动还是后面元素向后面移动(谁小移动谁)。而在删除元素的时候,考虑是将前面元素后移覆盖需要移除元素的地方还是后面元素前移覆盖(谁小移动谁)。移动完以后要析构冗余的元素,释放冗余的缓存区。
三、deque的源码剖析
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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));
- }
-
-
- template <class T, class Ref, class Ptr, size_t 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)); }
-
- 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;
-
- typedef __deque_iterator self;
-
-
- T* cur;
- T* first;
- T* last;
- map_pointer node;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- __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) {}
-
- reference operator*() const { return *cur; }
-
-
- difference_type operator-(const self& x) const
- {
- return difference_type(buffer_size()) * (node - x.node - 1) +
- (cur - first) + (x.last - x.cur);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- self& operator++()
- {
- ++cur;
- if (cur == last)
- {
- set_node(node + 1);
- cur = first;
- }
- return *this;
- }
-
-
-
- self operator++(int)
- {
- self tmp = *this;
- ++*this;
- return tmp;
- }
-
-
-
-
- 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+=(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;
- }
-
- 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;
- }
-
- reference operator[](difference_type n) const { return *(*this + 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);
- }
-
- void set_node(map_pointer new_node)
- {
- node = new_node;
- first = *new_node;
- last = first + difference_type(buffer_size());
- }
- };
-
-
-
- template <class T, class Alloc = alloc, size_t BufSiz = 0>
- class deque
- {
- public:
- typedef T value_type;
- typedef value_type* pointer;
- typedef value_type& reference;
- typedef size_t size_type;
- typedef ptrdiff_t difference_type;
-
- public:
- typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
-
- protected:
-
- typedef pointer* map_pointer;
-
-
- typedef simple_alloc<value_type, Alloc> data_allocator;
- 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; }
-
- protected:
- iterator start;
- iterator finish;
-
-
- map_pointer map;
- size_type map_size;
-
- public:
- iterator begin() { return start; }
- iterator end() { return finish; }
-
-
-
- reference operator[](size_type n) { return start[difference_type(n)]; }
-
- reference front() { return *start; }
- reference back()
- {
- 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; }
-
- public:
- deque() : start(), finish(), map(0), map_size(0)
- {
- create_map_and_nodes(0);
- }
-
- 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()
- {
- destroy(start, finish);
- destroy_map_and_nodes();
- }
-
- 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;
- }
-
- 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);
- }
-
- 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();
- }
-
- 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);
- }
- }
-
- iterator insert(iterator position) { return insert(position, value_type()); }
-
-
- void insert(iterator pos, size_type n, const value_type& 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 resize(size_type new_size) { resize(new_size, value_type()); }
-
- 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();
-
- protected:
-
-
- void push_back_aux(const value_type& t);
- void push_front_aux(const value_type& t);
- void pop_back_aux();
- void pop_front_aux();
-
- iterator insert_aux(iterator pos, const value_type& x);
- void insert_aux(iterator pos, size_type n, const value_type& x);
-
-
- pointer allocate_node() { return data_allocator::allocate(buffer_size()); }
-
-
- void deallocate_node(pointer n)
- {
- data_allocator::deallocate(n, buffer_size());
- }
-
- };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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;
- }
- }
-
- 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;
- }
-
-
-
-
- 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);
- }
- catch(...)
- {
- start.set_node(start.node + 1);
- start.cur = start.first;
- deallocate_node(*(start.node - 1));
- throw;
- }
- }
-
-
- 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;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- template <class T, class Alloc, size_t BufSize>
- typename deque<T, Alloc, BufSize>::iterator
- deque<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;
- }
STL源码分析--deque
原文:http://blog.csdn.net/yusiguyuan/article/details/38878189