STL源码分析--deque

一、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的源码剖析

[cpp] view plaincopy

  1. //   deque的特性:
  2. //   对于任何一个迭代器i
  3. //     i.node是map array中的某元素的地址. i.node的内容是一个指向某个结点的头的指针
  4. //     i.first == *(i.node)
  5. //     i.last  == i.first + node_size
  6. //     i.cur是一个指向[i.first, i.last)之间的指针
  7. //       注意: 这意味着i.cur永远是一个可以解引用的指针,
  8. //            即使其是一个指向结尾后元素的迭代器
  9. //
  10. //   起点和终点总是非奇异(nonsingular)的迭代器.
  11. //     注意: 这意味着空deque一定有一个node, 而一个具有N个元素的deque
  12. //          (N是Buffer Size)一定有有两个nodes
  13. //
  14. //   对于除了start.node和finish.node之外的每一个node, 每一个node中的元素
  15. //   都是一个初始化过的对象. 如果start.node == finish.node,
  16. //   那么[start.cur, finish.cur)都是未初始化的空间.
  17. //   否则, [start.cur, start.last)和[finish.first, finish.cur)都是初始化的对象,
  18. //   而[start.first, start.cur)和[finish.cur, finish.last)是未初始化的空间
  19. //
  20. //   [map, map + map_size)是一个合法的非空区间
  21. //   [start.node, finish.node]是内含在[map, map + map_size)区间的合法区间
  22. //   一个在[map, map + map_size)区间内的指针指向一个分配过的node,
  23. //   当且仅当此指针在[start.node, finish.node]区间内
  24. inline size_t __deque_buf_size(size_t n, size_t sz)
  25. {
  26. return n != 0 ? n : (sz < 512 ? size_t(512 / sz) : size_t(1));
  27. }
  28. // __deque_iterator的数据结构
  29. template <class T, class Ref, class Ptr, size_t BufSiz>
  30. struct __deque_iterator
  31. {
  32. typedef __deque_iterator<T, T&, T*>             iterator;
  33. typedef __deque_iterator<T, const T&, const T*> const_iterator;
  34. static size_t buffer_size() {return __deque_buf_size(0, sizeof(T)); }
  35. typedef random_access_iterator_tag iterator_category;
  36. typedef T value_type;
  37. typedef Ptr pointer;
  38. typedef Ref reference;
  39. typedef size_t size_type;
  40. typedef ptrdiff_t difference_type;
  41. typedef T** map_pointer;
  42. typedef __deque_iterator self;
  43. // 保持与容器的联结
  44. T* cur;       // 此迭代器所指之缓冲区中的现行元素
  45. T* first;     // 此迭代器所指之缓冲区的头
  46. T* last;      // 此迭代器所指之缓冲区的尾(含备用空间)
  47. map_pointer node;    // 指向管控中心
  48. ////////////////////////////////////////////////////////////////////////////////
  49. // 这个是deque内存管理的关键, 其模型如下
  50. ////////////////////////////////////////////////////////////////////////////////
  51. //
  52. //       ---------------------------------------------
  53. // map-->|   |   |   |   |   |   | ..... |   |   |   |<------------------
  54. //       ---------------------------------------------                  |
  55. //             |                                                        |
  56. //             |                                                        |
  57. //             |   node                                                 |
  58. //             |   缓冲区buffer, 这里实际存储元素                          |
  59. //             |   ---------------------------------------------        |
  60. //             --->|   |   |   |   |   |   | ..... |   |   | X |        |
  61. //                 ---------------------------------------------        |
  62. //                   ↑       ↑                             ↑            |
  63. //             ------        |                             |            |
  64. //             |             |                             |            |
  65. //             |   -----------   ---------------------------            |
  66. //             ----|-----        |                                      |
  67. //                 |    |        |                                      |
  68. //                 |    |        |                                      |
  69. //                 |    |        |                                      |
  70. //              ---------------------------                             |
  71. //              | cur | first | end | map |------------------------------
  72. //              ---------------------------
  73. //              迭代器, 其内部维护着一个缓冲区状态
  74. ////////////////////////////////////////////////////////////////////////////////
  75. __deque_iterator(T* x, map_pointer y)
  76. : cur(x), first(*y), last(*y + buffer_size()), node(y) {}
  77. __deque_iterator() : cur(0), first(0), last(0), node(0) {}
  78. __deque_iterator(const iterator& x)
  79. : cur(x.cur), first(x.first), last(x.last), node(x.node) {}
  80. reference operator*() const { return *cur; }
  81. // 判断两个迭代器间的距离
  82. difference_type operator-(const self& x) const
  83. {
  84. return difference_type(buffer_size()) * (node - x.node - 1) +
  85. (cur - first) + (x.last - x.cur);
  86. }
  87. ////////////////////////////////////////////////////////////////////////////////
  88. // 下面重载的这些运算符是让deque从外界看上去维护的是一段连续空间的关键!!!
  89. // 前缀自增
  90. ////////////////////////////////////////////////////////////////////////////////
  91. // 如果当前迭代器指向元素是当前缓冲区的最后一个元素,
  92. // 则将迭代器状态调整为下一个缓冲区的第一个元素
  93. ////////////////////////////////////////////////////////////////////////////////
  94. // 不是当前缓冲区最后一个元素
  95. //
  96. // 执行前缀自增前的状态
  97. // first          cur                     end
  98. // ↓               ↓                       ↓
  99. // ---------------------------------------------
  100. // |   |   |   |   |   |   | ..... |   |   | X | <----- 当前缓冲区
  101. // ---------------------------------------------
  102. //
  103. // 执行完成后的状态
  104. // first              cur                 end
  105. // ↓                   ↓                   ↓
  106. // ---------------------------------------------
  107. // |   |   |   |   |   |   | ..... |   |   | X | <----- 当前缓冲区
  108. // ---------------------------------------------
  109. //
  110. ////////////////////////////////////////////////////////////////////////////////
  111. // 当前元素为当前缓冲区的最后一个元素
  112. //
  113. // 执行前缀自增前的状态
  114. // first                              cur end
  115. // ↓                                   ↓   ↓
  116. // ---------------------------------------------
  117. // |   |   |   |   |   |   | ..... |   |   | X | <----- 当前缓冲区
  118. // ---------------------------------------------
  119. //
  120. // 执行完成后的状态
  121. // first                                  end
  122. // ↓                                       ↓
  123. // ---------------------------------------------
  124. // |   |   |   |   |   |   | ..... |   |   | X | <----- 下一缓冲区
  125. // ---------------------------------------------
  126. // ↑
  127. // cur
  128. //
  129. ////////////////////////////////////////////////////////////////////////////////
  130. self& operator++()
  131. {
  132. ++cur;    // 切换至下一个元素
  133. if (cur == last)    // 如果已达到缓冲区的尾端
  134. {
  135. set_node(node + 1);    // 就切换至下一节点(亦即缓冲区)
  136. cur = first;           // 的第一个元素
  137. }
  138. return *this;
  139. }
  140. // 后缀自增
  141. // 返回当前迭代器的一个副本, 并调用前缀自增运算符实现迭代器自身的自增
  142. self operator++(int)
  143. {
  144. self tmp = *this;
  145. ++*this;
  146. return tmp;
  147. }
  148. // 前缀自减, 处理方式类似于前缀自增
  149. // 如果当前迭代器指向元素是当前缓冲区的第一个元素
  150. // 则将迭代器状态调整为前一个缓冲区的最后一个元素
  151. self& operator--()
  152. {
  153. if (cur == first)    // 如果已达到缓冲区的头端
  154. {
  155. set_node(node - 1);    // 就切换至前一节点(亦即缓冲区)
  156. cur = last;            // 的最后一个元素
  157. }
  158. --cur;
  159. return *this;
  160. }
  161. self operator--(int)
  162. {
  163. self tmp = *this;
  164. --*this;
  165. return tmp;
  166. }
  167. ////////////////////////////////////////////////////////////////////////////////
  168. // 将迭代器向前移动n个元素, n可以为负
  169. ////////////////////////////////////////////////////////////////////////////////
  170. //                     operator+=(difference_type n)
  171. //                                   ↓
  172. //                      offset = n + (cur - first)
  173. //                                   |
  174. //                                   |---------- offset > 0 ? &&
  175. //                                   |           移动后是否超出当前缓冲区?
  176. //               ----------------------------
  177. //           No  |                          |  Yes
  178. //               |                          |
  179. //               ↓                          |---------- offset > 0?
  180. //           cur += n;                      |
  181. //                              ----------------------------
  182. //                          Yes |                          | No
  183. //                              |                          |
  184. //                              ↓                          |
  185. //                   计算要向后移动多少个缓冲区                |
  186. //                   node_offset =                         |
  187. //                   offset / difference_type              |
  188. //                   (buffer_size());                      ↓
  189. //                              |           计算要向前移动多少个缓冲区
  190. //                              |           node_offset = -difference_type
  191. //                              |           ((-offset - 1) / buffer_size()) - 1;
  192. //                              |                          |
  193. //                              ----------------------------
  194. //                                           |
  195. //                                           |
  196. //                                           ↓
  197. //                                       调整缓冲区
  198. //                              set_node(node + node_offset);
  199. //                                    计算并调整cur指针
  200. ////////////////////////////////////////////////////////////////////////////////
  201. // 以下实现随机存取。迭代器可以直接跳跃n个距离
  202. self& operator+=(difference_type n)
  203. {
  204. difference_type offset = n + (cur - first);
  205. if (offset >= 0 && offset < difference_type(buffer_size()))
  206. cur += n;        // 目标位置在同一缓冲区内
  207. else
  208. {           // 目标位置不在同一缓冲区内
  209. difference_type node_offset =
  210. offset > 0 ? offset / difference_type(buffer_size())
  211. : -difference_type((-offset - 1) / buffer_size()) - 1;
  212. // 切换至正确的节点(亦即缓冲区)
  213. set_node(node + node_offset);
  214. // 切换至正确的元素
  215. cur = first + (offset - node_offset * difference_type(buffer_size()));
  216. }
  217. return *this;
  218. }
  219. self operator+(difference_type n) const
  220. {
  221. self tmp = *this;
  222. // 这里调用了operator +=()可以自动调整指针状态
  223. return tmp += n;
  224. }
  225. // 将n变为-n就可以使用operator +=()了,
  226. self& operator-=(difference_type n) { return *this += -n; }
  227. self operator-(difference_type n) const
  228. {
  229. self tmp = *this;
  230. return tmp -= n;
  231. }
  232. reference operator[](difference_type n) const { return *(*this + n); }
  233. bool operator==(const self& x) const { return cur == x.cur; }
  234. bool operator!=(const self& x) const { return !(*this == x); }
  235. bool operator<(const self& x) const
  236. {
  237. return (node == x.node) ? (cur < x.cur) : (node < x.node);
  238. }
  239. void set_node(map_pointer new_node)
  240. {
  241. node = new_node;
  242. first = *new_node;
  243. last = first + difference_type(buffer_size());
  244. }
  245. };
  246. // deque的数据结构
  247. template <class T, class Alloc = alloc, size_t BufSiz = 0>
  248. class deque
  249. {
  250. public:                         // Basic types
  251. typedef T value_type;
  252. typedef value_type* pointer;
  253. typedef value_type& reference;
  254. typedef size_t size_type;
  255. typedef ptrdiff_t difference_type;
  256. public:                         // Iterators
  257. typedef __deque_iterator<T, T&, T*, BufSiz>       iterator;
  258. protected:                      // Internal typedefs
  259. typedef pointer* map_pointer;
  260. // 这个提供STL标准的allocator接口, 见<stl_alloc.h>
  261. typedef simple_alloc<value_type, Alloc> data_allocator;
  262. typedef simple_alloc<pointer, Alloc> map_allocator;
  263. // 获取缓冲区最大存储元素数量
  264. static size_type buffer_size()
  265. {
  266. return __deque_buf_size(BufSiz, sizeof(value_type));
  267. }
  268. static size_type initial_map_size() { return 8; }
  269. protected:                      // Data members
  270. iterator start;               // 起始缓冲区
  271. iterator finish;              // 最后一个缓冲区
  272. // 指向map, map是一个连续的空间, 其每个元素都是一个指针,指向一个节点(缓冲区)
  273. map_pointer map;
  274. size_type map_size;   // map容量
  275. public:
  276. iterator begin() { return start; }
  277. iterator end() { return finish; }
  278. // 提供随机访问能力, 其调用的是迭代器重载的operator []
  279. // 其实际地址需要进行一些列的计算, 效率有损失
  280. reference operator[](size_type n) { return start[difference_type(n)]; }
  281. reference front() { return *start; }
  282. reference back()
  283. {
  284. iterator tmp = finish;
  285. --tmp;
  286. return *tmp;
  287. }
  288. // 当前容器拥有的元素个数, 调用迭代器重载的operator -
  289. size_type size() const { return finish - start;; }
  290. size_type max_size() const { return size_type(-1); }
  291. // deque为空的时, 只有一个缓冲区
  292. bool empty() const { return finish == start; }
  293. public:                         // Constructor, destructor.
  294. deque() : start(), finish(), map(0), map_size(0)
  295. {
  296. create_map_and_nodes(0);
  297. }
  298. deque(size_type n, const value_type& value)
  299. : start(), finish(), map(0), map_size(0)
  300. {
  301. fill_initialize(n, value);
  302. }
  303. deque(int n, const value_type& value)
  304. : start(), finish(), map(0), map_size(0)
  305. {
  306. fill_initialize(n, value);
  307. }
  308. ~deque()
  309. {
  310. destroy(start, finish);     // <stl_construct.h>
  311. destroy_map_and_nodes();
  312. }
  313. deque& operator= (const deque& x)
  314. {
  315. // 其实我觉得把这个操作放在if内效率更高
  316. const size_type len = size();
  317. if (&x != this)
  318. {
  319. // 当前容器比x容器拥有元素多, 析构多余元素
  320. if (len >= x.size())
  321. erase(copy(x.begin(), x.end(), start), finish);
  322. // 将x所有超出部分的元素使用insert()追加进去
  323. else {
  324. const_iterator mid = x.begin() + difference_type(len);
  325. copy(x.begin(), mid, start);
  326. insert(finish, mid, x.end());
  327. }
  328. }
  329. return *this;
  330. }
  331. public:
  332. void push_back(const value_type& t)
  333. {
  334. // 最后缓冲区尚有两个(含)以上的元素备用空间
  335. if (finish.cur != finish.last - 1)
  336. {
  337. construct(finish.cur, t);     // 直接在备用空间上构造元素
  338. ++finish.cur;     // 调整最后缓冲区的使用状态
  339. }
  340. // 容量已满就要新申请内存了
  341. else
  342. push_back_aux(t);
  343. }
  344. void push_front(const value_type& t)
  345. {
  346. if (start.cur != start.first)      // 第一缓冲区尚有备用空间
  347. {
  348. construct(start.cur - 1, t);   // 直接在备用空间上构造元素
  349. --start.cur;     // 调整第一缓冲区的使用状态
  350. }
  351. else    // 第一缓冲区已无备用空间
  352. push_front_aux(t);
  353. }
  354. void pop_back()
  355. {
  356. if (finish.cur != finish.first)    // 最后缓冲区有一个(或更多)元素
  357. {
  358. --finish.cur;    // 调整指针,相当于排除了最后元素
  359. destroy(finish.cur);    // 将最后元素析构
  360. }
  361. else
  362. // 最后缓冲区没有任何元素
  363. pop_back_aux();    // 这里将进行缓冲区的释放工作
  364. }
  365. void pop_front()
  366. {
  367. if (start.cur != start.last - 1)    // 第一缓冲区有两个(或更多)元素
  368. {
  369. destroy(start.cur);    // 将第一元素析构
  370. ++start.cur;           //调整指针,相当于排除了第一元素
  371. }
  372. else
  373. // 第一缓冲区仅有一个元素
  374. pop_front_aux();    // 这里将进行缓冲区的释放工作
  375. }
  376. public:                         // Insert
  377. ////////////////////////////////////////////////////////////////////////////////
  378. // 在指定位置前插入元素
  379. ////////////////////////////////////////////////////////////////////////////////
  380. //             insert(iterator position, const value_type& x)
  381. //                                   |
  382. //                                   |---------------- 判断插入位置
  383. //                                   |
  384. //               -----------------------------------------------
  385. // deque.begin() |          deque.emd() |                      |
  386. //               |                      |                      |
  387. //               ↓                      ↓                      |
  388. //         push_front(x);         push_back(x);                |
  389. //                                                             ↓
  390. //                                                 insert_aux(position, x);
  391. //                                                 具体剖析见后面实现
  392. ////////////////////////////////////////////////////////////////////////////////
  393. iterator insert(iterator position, const value_type& x)
  394. {
  395. // 如果是在deque的最前端插入, 那么直接push_front()即可
  396. if (position.cur == start.cur)
  397. {
  398. push_front(x);
  399. return start;
  400. }
  401. // 如果是在deque的末尾插入, 直接调用push_back()
  402. else if (position.cur == finish.cur)
  403. {
  404. push_back(x);
  405. iterator tmp = finish;
  406. --tmp;
  407. return tmp;
  408. }
  409. else
  410. {
  411. return insert_aux(position, x);
  412. }
  413. }
  414. iterator insert(iterator position) { return insert(position, value_type()); }
  415. // 详解见实现部分
  416. void insert(iterator pos, size_type n, const value_type& x);
  417. void insert(iterator pos, int n, const value_type& x)
  418. {
  419. insert(pos, (size_type) n, x);
  420. }
  421. void insert(iterator pos, long n, const value_type& x)
  422. {
  423. insert(pos, (size_type) n, x);
  424. }
  425. void resize(size_type new_size) { resize(new_size, value_type()); }
  426. public:                         // Erase
  427. iterator erase(iterator pos)
  428. {
  429. iterator next = pos;
  430. ++next;
  431. // 清除点之前的元素个数
  432. difference_type index = pos - start;
  433. // 如果清除点之前的元素个数比较少, 哪部分少就移动哪部分
  434. if (index < (size() >> 1))
  435. {
  436. // 就移动清除点之前的元素
  437. copy_backward(start, pos, next);
  438. pop_front();   // 移动完毕,最前一个元素冗余,去除之
  439. }
  440. else   // 如果清除点之后的元素个数比较少
  441. {
  442. copy(next, finish, pos);  // 就移动清除点之后的元素
  443. pop_back();   // 移动完毕,最后一个元素冗余,去除之
  444. }
  445. return start + index;
  446. }
  447. iterator erase(iterator first, iterator last);
  448. void clear();
  449. protected:
  450. // 详解见实现部分
  451. void push_back_aux(const value_type& t);
  452. void push_front_aux(const value_type& t);
  453. void pop_back_aux();
  454. void pop_front_aux();
  455. iterator insert_aux(iterator pos, const value_type& x);
  456. void insert_aux(iterator pos, size_type n, const value_type& x);
  457. // 分配内存, 不进行构造
  458. pointer allocate_node() { return data_allocator::allocate(buffer_size()); }
  459. // 释放内存, 不进行析构
  460. void deallocate_node(pointer n)
  461. {
  462. data_allocator::deallocate(n, buffer_size());
  463. }
  464. };
  465. ////////////////////////////////////////////////////////////////////////////////
  466. // 清除[first, last)区间的所有元素
  467. ////////////////////////////////////////////////////////////////////////////////
  468. //                  erase(iterator first, iterator last)
  469. //                                   |
  470. //                                   |---------------- 是否要删除整个区间?
  471. //                                   |
  472. //               ------------------------------------------
  473. //           Yes |                                        | No
  474. //               |                                        |
  475. //               ↓                                        | --- 判断哪侧元素少
  476. //            clear();                                    ↓
  477. //       -----------------------------------------------------------------
  478. // 左侧少 |                                                         右侧少 |
  479. //       |                                                               |
  480. //       ↓                                                               ↓
  481. //   copy_backward(start, first, last);            copy(last, finish, first);
  482. //   new_start = start + n;                        new_finish = finish - n;
  483. //   析构多余的元素                                  析构多余的元素
  484. //   destroy(start, new_start);                    destroy(new_finish, finish);
  485. //   释放多余内存空间                                释放多余内存空间
  486. //   for (...)                                     for (...)
  487. //      ...                                             ...
  488. //   更新map状态                                    更新map状态
  489. ////////////////////////////////////////////////////////////////////////////////
  490. template <class T, class Alloc, size_t BufSize>
  491. deque<T, Alloc, BufSize>::iterator
  492. deque<T, Alloc, BufSize>::erase(iterator first, iterator last)
  493. {
  494. if (first == start && last == finish)   // 如果清除区间是整个deque
  495. {
  496. clear();              // 直接调用clear()即可
  497. return finish;
  498. }
  499. else
  500. {
  501. difference_type n = last - first;   // 清除区间的长度
  502. difference_type elems_before = first - start;   // 清除区间前方的元素个数
  503. if (elems_before < (size() - n) / 2)   // 如果前方的元素个数比较少
  504. {
  505. copy_backward(start, first, last);  // 向后移动前方元素(覆盖清除区间)
  506. iterator new_start = start + n;     // 标记deque的新起点
  507. destroy(start, new_start);          // 移动完毕,将冗余的元素析构
  508. // 以下将冗余的缓冲区释放
  509. for (map_pointer cur = start.node; cur < new_start.node; ++cur)
  510. data_allocator::deallocate(*cur, buffer_size());
  511. start = new_start;   // 设定deque的新起点
  512. }
  513. else    // 如果清除区间后方的元素个数比较少
  514. {
  515. copy(last, finish, first);  // 向前移动后方元素(覆盖清除区间)
  516. iterator new_finish = finish - n;     // 标记deque的新尾点
  517. destroy(new_finish, finish);          // 移动完毕,将冗余的元素析构
  518. // 以下将冗余的缓冲区释放
  519. for (map_pointer cur = new_finish.node + 1; cur <= finish.node; ++cur)
  520. data_allocator::deallocate(*cur, buffer_size());
  521. finish = new_finish;   // 设定deque的新尾点
  522. }
  523. return start + elems_before;
  524. }
  525. }
  526. template <class T, class Alloc, size_t BufSize>
  527. void deque<T, Alloc, BufSize>::clear()
  528. {
  529. // 以下针对头尾以外的每一个缓冲区
  530. for (map_pointer node = start.node + 1; node < finish.node; ++node)
  531. {
  532. // 将缓冲区内的所有元素析构
  533. destroy(*node, *node + buffer_size());
  534. // 释放缓冲区内存
  535. data_allocator::deallocate(*node, buffer_size());
  536. }
  537. if (start.node != finish.node)   // 至少有头尾两个缓冲区
  538. {
  539. destroy(start.cur, start.last);  // 将头缓冲区的目前所有元素析构
  540. destroy(finish.first, finish.cur);  // 将尾缓冲区的目前所有元素析构
  541. // 以下释放尾缓冲区。注意:头缓冲区保留
  542. data_allocator::deallocate(finish.first, buffer_size());
  543. }
  544. else   // 只有一个缓冲区
  545. destroy(start.cur, finish.cur);   // 将此唯一缓冲区内的所有元素析构
  546. // 注意:并不释放缓冲区空间,这唯一的缓冲区将保留
  547. finish = start;   // 调整状态
  548. }
  549. // 只有当finish.cur == finish.last - 1 时才会被调用
  550. // 也就是说,只有当最后一个缓冲区只剩下一个备用元素空间时才会被调用
  551. template <class T, class Alloc, size_t BufSize>
  552. void deque<T, Alloc, BufSize>::push_back_aux(const value_type& t)
  553. {
  554. value_type t_copy = t;
  555. reserve_map_at_back();
  556. *(finish.node + 1) = allocate_node();    // 配置一个新节点(缓冲区)
  557. __STL_TRY
  558. {
  559. construct(finish.cur, t_copy);         // 针对标的元素设值
  560. finish.set_node(finish.node + 1);      // 改变finish,令其指向新节点
  561. finish.cur = finish.first;             // 设定finish的状态
  562. }
  563. __STL_UNWIND(deallocate_node(*(finish.node + 1)));
  564. }
  565. // Called only if start.cur == start.first.
  566. template <class T, class Alloc, size_t BufSize>
  567. void deque<T, Alloc, BufSize>::push_front_aux(const value_type& t)
  568. {
  569. value_type t_copy = t;
  570. reserve_map_at_front();
  571. *(start.node - 1) = allocate_node();
  572. __STL_TRY
  573. {
  574. start.set_node(start.node - 1);        // 改变start,令其指向新节点
  575. start.cur = start.last - 1;            // 设定start的状态
  576. construct(start.cur, t_copy);          // 针对标的元素设值
  577. }
  578. catch(...)
  579. {
  580. start.set_node(start.node + 1);
  581. start.cur = start.first;
  582. deallocate_node(*(start.node - 1));
  583. throw;
  584. }
  585. }
  586. // 只有当 finish.cur == finish.first 时才会被调用
  587. template <class T, class Alloc, size_t BufSize>
  588. void deque<T, Alloc, BufSize>:: pop_back_aux()
  589. {
  590. deallocate_node(finish.first);      // 释放最后一个缓冲区
  591. finish.set_node(finish.node - 1);   // 调整finish状态,使指向
  592. finish.cur = finish.last - 1;       // 上一个缓冲区的最后一个元素
  593. destroy(finish.cur);                // 将该元素析构
  594. }
  595. // 只有当 start.cur == start.last - 1 时才会被调用
  596. template <class T, class Alloc, size_t BufSize>
  597. void deque<T, Alloc, BufSize>::pop_front_aux()
  598. {
  599. destroy(start.cur);    // 将第一个缓冲区的第一个(也是最后一个、唯一一个)元素析构
  600. deallocate_node(start.first);    // 释放第一缓冲区
  601. start.set_node(start.node + 1);  // 调整start状态,使指向
  602. start.cur = start.first;         // 下一个缓冲区的第一个元素
  603. }
  604. ////////////////////////////////////////////////////////////////////////////////
  605. // 在指定位置前插入元素
  606. ////////////////////////////////////////////////////////////////////////////////
  607. //              insert_aux(iterator pos, const value_type& x)
  608. //                                   |
  609. //                                   |----------- 判断pos前端元素少还是后端元素少
  610. //                                   |
  611. //               -----------------------------------------------
  612. //         前端少 |                                       后端少 |
  613. //               |                                             |
  614. //               ↓                                             |
  615. //           进行相关操作                                   进行相关操作
  616. ////////////////////////////////////////////////////////////////////////////////
  617. // 下面以pos前面元素少的情形进行说明, 为了简化, 假设操作不会超过一个缓冲区区间
  618. //
  619. // 插入前状态
  620. //           start            pos                                 end
  621. //             ↓               ↓                                   ↓
  622. // ---------------------------------------------------------------------
  623. // |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   | X |
  624. // ---------------------------------------------------------------------
  625. //
  626. // 需要进行操作的区间
  627. //                需要拷贝的区间
  628. //                 -------------
  629. //       start     |           |                                  end
  630. //         ↓       ↓           ↓                                   ↓
  631. // ---------------------------------------------------------------------
  632. // |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   | X |
  633. // ---------------------------------------------------------------------
  634. //             ↑   ↑       ↑   ↑
  635. //        front1   |       |   |
  636. //                 |       |   |
  637. //            front2       |   |
  638. //                         |   |
  639. //                       pos   |
  640. //                             |
  641. //                          pos1
  642. // 拷贝操作完成后
  643. //
  644. //         这是[front2, pos1)
  645. //             ------------- --------- 这里是给待插入元素预留的空间
  646. //       start |           | |                                    end
  647. //         ↓   ↓           ↓ ↓                                     ↓
  648. // ---------------------------------------------------------------------
  649. // |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   | X |
  650. // ---------------------------------------------------------------------
  651. //         ↑
  652. //   这里存储的是原来的front()
  653. //
  654. ////////////////////////////////////////////////////////////////////////////////
  655. template <class T, class Alloc, size_t BufSize>
  656. typename deque<T, Alloc, BufSize>::iterator
  657. deque<T, Alloc, BufSize>::insert_aux(iterator pos, const value_type& x)
  658. {
  659. difference_type index = pos - start;   // 插入点之前的元素个数
  660. value_type x_copy = x;
  661. // 前面的时候用的移位操作, 这里怎么不用了呢^_^?
  662. if (index < size() / 2)    // 如果插入点之前的元素个数比较少
  663. {
  664. push_front(front());       // 在最前端加入与第一元素同值的元素
  665. iterator front1 = start;   // 以下标示记号,然后进行元素移动
  666. ++front1;
  667. iterator front2 = front1;
  668. ++front2;
  669. pos = start + index;
  670. iterator pos1 = pos;
  671. ++pos1;
  672. copy(front2, pos1, front1);    // 元素移动
  673. }
  674. else    // 插入点之后的元素个数比较少
  675. {
  676. push_back(back());         // 在最尾端加入与最后元素同值的元素
  677. iterator back1 = finish;   // 以下标示记号,然后进行元素移动
  678. --back1;
  679. iterator back2 = back1;
  680. --back2;
  681. pos = start + index;
  682. copy_backward(pos, back2, back1);    // 元素移动
  683. }
  684. *pos = x_copy;    // 在插入点上设定新值
  685. return pos;
  686. }
时间: 2024-08-06 20:01:11

STL源码分析--deque的相关文章

STL源码分析--仿函数 &amp; 配接器

STL源码分析-仿函数 & 配接器 仿函数就是函数对象.就实现观点而言,仿函数其实就是一个"行为类似函数"的对象.为了能够"行为类似函数",其类别定义中必须自定义(或说改写.重载)function call 运算子(operator()),拥有这样的运算子后,我们就可以在仿函数的对象后面加上一对小括号,以此调用仿函数所定义的operator().仿函数作为可配接的关键因素. 配接器在STL组件的灵活组合运用功能上,扮演着轴承.转换器的角色,adapter的定

stl源码分析之hash table

本文主要分析g++ stl中哈希表的实现方法.stl中,除了以红黑树为底层存储结构的map和set,还有用哈希表实现的hash_map和hash_set.map和set的查询时间是对数级的,而hash_map和hash_set更快,可以达到常数级,不过哈希表需要更多内存空间,属于以空间换时间的用法,而且选择一个好的哈希函数也不那么容易. 一. 哈希表基本概念 哈希表,又名散列表,是根据关键字直接访问内存的数据结构.通过哈希函数,将键值映射转换成数组中的位置,就可以在O(1)的时间内访问到数据.举

stl源码分析之list

本文主要分析gcc4.8版本的stl list的源码实现,与vector的线性空间结构不同,list的节点是任意分散的,节点之间通过指针连接,好处是在任何位置插入删除元素都只需要常数时间,缺点是不能随机访问,查询复杂度是O(n),n为list中的元素个数.所以list非常适合应用与数据插入删除频繁的场景. 一. list节点 list节点定义如下, struct _List_node_base { _List_node_base* _M_next; _List_node_base* _M_pre

stl源码分析之priority queue

前面两篇介绍了gcc4.8的vector和list的源码实现,这是stl最常用了两种序列式容器.除了容器之外,stl还提供了一种借助容器实现特殊操作的组件,谓之适配器,比如stack,queue,priority queue等,本文就介绍gcc4.8的priority queue的源码实现. 顾名思义,priority queue是带有优先级的队列,所以元素必须提供<操作符,与vector和list不同,priority queue允许加入元素,但是取出时只能取出优先级最高的元素. 一. pri

stl源码分析之vector

上篇简单介绍了gcc4.8提供的几种allocator的实现方法和作用,这是所有stl组件的基础,容器必须通过allocator申请分配内存和释放内存,至于底层是直接分配释放内存还是使用内存池等方法就不是组件需要考虑的事情.这篇文章开始分析gcc4.8 stl的容器源码实现.stl的容器分为序列式容器和关联式容器,前者包括vector,list,queue以及stack等常用数据结构,后者包含了map,set以及hash table等比较高级的结构,本文就从使用最广泛也是最基础的vector开始

STL源码分析--空间配置器的底层实现 (二)

STL源码分析-空间配置器 空间配置器中门道 在STL中的容器里都是使用统一的空间配置器,空间配置器就是管理分配内存和销毁内存的.在STL将在heap空间创建一个对象分为两个步骤,第一是申请一块内存,第二是在这块内存中初始化一个对象.首先申请空间是由malloc提供,初始化一个对象时由constructor管理.销毁一个对象也是由两步骤完成,第一是销毁空间上的对象,第二是释放这块内存. 同时,STL的空间配置器分为两级内存,如果申请的内存空间大于128KB,那么就使用第一级空间配置,如果小于,那

STL源码分析--仿函数 &amp; 模板的模板参数 &amp; 临时对象

STL源码分析-使用的一些特殊语法 关于泛型编程中用到的一些特殊语法,这些语法也适用于平常的模板编程 1.  类模板中使用静态成员变量 Static成员变量在类模板中并不是很特殊,同时这个变量不属于对象,属于实例化以后的这个类类型.每一个实例化对应一个static变量 2.  类模板中可以再有模板成员 3.  模板参数可以根据前一个模板参数而设定默认值 4.  类模板可以拥有非类型的模板参数 所谓非类型的模板参数就是内建型的模板参数 Template <class T,class Alloc =

STL 源码分析 # stl_iterator &amp; stl_iterator_base #

STL 源码分析 # stl_iterator_base && stl_iterator # 这里能很清楚的看到各个基础类型的继承关系 template <class _Tp, class _Distance> struct input_iterator { typedef input_iterator_tag iterator_category; typedef _Tp value_type; typedef _Distance difference_type; typede

STL源码分析--算法

STL源码剖析-算法 在STL中的算法中一些算法是可以根据算法名字来判断算法作用的.所有算法的参数都是迭代器,不过不同的算法调用的迭代器类型也是不同的.多有的STL算法都作用在由迭代器{first,lase)所表示出来的区间上.拷贝(copy)交换(swap)替换(replace)填写(fill)删除(remove)排列组合(permutation)分割(partition)随机重排(random shuffling)排序(sort)计算(accumulate)计数(count)匹配(searc