[C++]Deque with iterator实现细节

Posted stary_yan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C++]Deque with iterator实现细节相关的知识,希望对你有一定的参考价值。

Deque with iterator实现细节

一、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,删除原来空间)、插入后元素是前面元素向前移动还是后面元素向后面移动(谁小移动谁)。而在删除元素的时候,考虑是将前面元素后移覆盖需要移除元素的地方还是后面元素前移覆盖(谁小移动谁)。移动完以后要析构冗余的元素,释放冗余的缓存区。

部分内容转自:STL源码剖析

//
//  Deque.h
//  deque
//
//  Created by 颜泽鑫 on 6/3/16.
//  Copyright © 2016 颜泽鑫. All rights reserved.
//

/*
 template <typename T>  // template declaration.
 class DequeIterator {
 public:
 typedef DequeIterator              iterator;
 typedef DequeIterator              const_iterator;
 typedef random_access_iterator_tag iterator_category;
 // iterator tag.
 typedef T                          value_type;
 typedef T*                         pointer;
 typedef T&                         reference;
 typedef size_t                     size_type;
 typedef ptrdiff_t                  difference_type;
 typedef T**                        map_pointer;
 typedef DequeIterator              self;

 T* cur;
 // pointer, pointing to the current element.
 T* first;
 // pointer, pointing to the first element in current buffer.
 T* last;
 // pointer, pointing to the last element in current buffer.
 map_pointer node;
 // pointer, pointing to the buffer.

 public:  // constructor
 DequeIterator(Tx x, map_pointer y);
 DequeIterator();
 DequeIterator(const iterator& x);

 public:
 // basic operation
 reference operator*() const;
 reference operator->() const;
 void set_node(map_pointer new_node);
 difference_type operator-(const self& x) const;

 // logic operation
 bool operator==(const self& x);
 bool operator!=(const self& x);
 bool operator<(const self& x);

 // random access
 self& operator++();
 self operator++(int);
 self& operator--();
 self operator--(int);
 self& operator+=(difference_type n);
 self& operator-=(difference_type n);
 self operator+(difference_type n) const;
 self operator-(difference_type n) const;
 reference operator[](differece_type n) const;
 */

#ifndef DequeIterator_
#define DequeIterator_
#include <iostream>
#define BUFFER_SIZE 10
using namespace std;
namespace Deque {
  template <typename T>
  class DequeIterator {
  public:
    typedef DequeIterator iterator;
    typedef const DequeIterator const_iterator;
    typedef random_access_iterator_tag iterator_category;
    // iterator tag.
    typedef T value_type;
    typedef T* pointer;
    typedef T& reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef T** map_pointer;
    typedef DequeIterator self;

    T* cur;    // pointer, pointing to the current element.
    T* first;  // pointer, pointing to the first element in current buffer.
    T* last;   // pointer, pointing to the last element in current buffer.
    map_pointer node;  // pointer, pointing to the buffer.

    static size_t buffer_size() { return BUFFER_SIZE; }

    DequeIterator(T* x, map_pointer y)
    : cur(x), first(*y), last(*y + buffer_size()), node(y) {}
    DequeIterator() : cur(0), first(0), last(0), node(0) {}
    DequeIterator(const iterator& x)
    : cur(x.cur), first(x.first), last(x.last), node(x.node) {}

    // return *current;定义解引用操作
    reference operator*() const { return *cur; }
    // return current;定义箭头操作符
    reference operator->() const { return cur; }
    // 判断两个迭代器是否相等
    bool operator==(const self& x) const { return cur == x.cur; }
    // 判断两个迭代器是否不相等
    bool operator!=(const self& x) const { return !(*this == x); }
    // 先比较map的node,在比较cur
    bool operator<(const self& x) const {
      return (node == x.node) ? (cur < x.cur) : (node < x.node);
    }
    // 将当前的迭代器设置为new_node,主要是设置node、first、last属性的值
    void set_node(map_pointer new_node) {
      node = new_node;
      first = *new_node;
      last = first + buffer_size();
    }

    difference_type operator-(const self& x) const {
      return difference_type(buffer_size()) * (node - x.node - 1) +
      (cur - first) + (x.last - x.cur);
    }
    /**
     *  Preincrement ++
     *  @return *this
     */
    self& operator++() {
      ++cur;
      if (cur == last) {
        set_node(node + 1);
        cur = first;
      }
      return *this;
    }
    /**
     *  Postincrement ++
     *  @param int just for placement.
     *  @return temporary value
     */
    self operator++(int) {
      self temp = *this;
      ++*this;
      return temp;
    }
    /**
     *  Predecrement
     *  @return *this
     */
    self& operator--() {
      if (cur == first) {
        set_node(node - 1);
        cur = last;
      }
      --cur;
      return *this;
    }
    /**
     *  Postdecrement --
     *  @param int just for placement
     *  @return temporary value
     */
    self operator--(int) {
      self temp = *this;
      --*this;
      return temp;
    }
    /**
     *  define increment for n steps
     *  inorder to realize random access
     *  @param n steps
     *  @return *this
     */
    self& operator+=(difference_type n) {
      difference_type offset = n + (cur - first);
      if (offset >= 0 && offset < difference_type(buffer_size())) {
        cur += n;
        // The destination is in the same buffer.
      } else {
        // The destination is in the different buffer.
        difference_type node_offset =
        offset > 0 ? offset / difference_type(buffer_size())
        : -difference_type((-offset - 1) / buffer_size()) - 1;
        // transfer to the right buffer node
        set_node(node + node_offset);
        // transfer to the right node
        cur = first + (offset - node_offset * difference_type(buffer_size()));
      }
      return *this;
    }
    //  The same as the += and we change the n to negative.
    self& operator-=(difference_type n) { return * this += -n; }
    /**
     *  increment n step but to get temporary object.
     *  @param n steps
     *  @return temporary object.
     */
    self operator+(difference_type n) const {
      self tmp = *this;
      //  call += operation.
      return tmp += n;
    }
    // The same as the += version and we change the n to negative.
    self operator-(difference_type n) const {
      self tmp = *this;
      return tmp -= n;
    }
    /**
     *  subscript operation
     *  random access
     *  @param n steps
     *  @return reference of object value.
     */
    reference operator[](difference_type n) const { return *(*this + n); }
  };
#endif /* DequeIterator */

  /*
   #include <new>
   #define MAP_SIZE 20
   template <typename T>
   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;
   typedef allocator<value_type> d_allocator;
   typedef allocator<pointer> m_allocator;
   typedef DequeIterator<T> iterator;
   typedef pointer* map_pointer;
   m_allocator map_allocator;
   d_allocator data_allocator;

   protected:
   static size_type buffer_size();
   static size_type initial_map_size();
   size_type max_size() const;

   protected:  // memeory operation
   pointer allocate_node();
   void deallocate_node(pointer n);
   void create_map_and_nodes(size_type num_elements);
   void reallocate_map(size_type nodes_to_add, bool add_at_front);
   void destroy_map_and_nodes();
   void reserve_map_at_back(size_type nodes_to_add = 1);
   void reserve_map_at_front(size_type nodes_to_add = 1);

   protected:
   iterator start;
   iterator finish;
   map_pointer map;
   size_type map_size;

   public:
   deque();
   ~deque();

   iterator begin();
   iterator end();
   reference front();
   reference back();
   reference operator[](size_type n);
   size_type size() const;
   bool empty() const;

   public:
   // elements operation
   void push_back(const value_type& value);
   void push_back_aux(const value_type& value);
   void push_front(const value_type& value);
   void push_front_aux(const value_type& value);
   void pop_back();
   void pop_front();
   void pop_back_aux();
   void pop_front_aux();

   void insert(iterator pos, const value_type& value = value_type());
   void insert_aux(iterator pos, const value_type& value);
   iterator erase(iterator pos);
   iterator erase(iterator first, iterator last);
   void clear();
   };
   */

#ifndef Deque
#define Deque
#include <new>
#define MAP_SIZE 20
  // we set the size of map is 20
  template <typename T>
  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;
    typedef allocator<value_type> d_allocator;
    typedef allocator<pointer> m_allocator;
    typedef DequeIterator<T> iterator;
    typedef pointer* map_pointer;
    m_allocator map_allocator;
    d_allocator data_allocator;

  protected:
    static size_type buffer_size() { return size_t(BUFFER_SIZE); }
    static size_type initial_map_size() { return 8; }
    size_type max_size() const { return size_type(-1); }

    // The functions are used to allocate and deallocate memory.

    /**
     *  allocate memory for node.
     *  @return pointer with memory.
     */
    pointer allocate_node() { return data_allocator.allocate(buffer_size()); }
    /**
     *  deallocate memory of node.
     *  @param n pointer of node.
     */
    void deallocate_node(pointer n) {
      data_allocator.deallocate(n, buffer_size());
    }
    /**
     *  create map and node for deque
     *  @param num_elements the number of elements
     */
    void create_map_and_nodes(size_type num_elements) {
      size_type num_nodes = num_elements / BUFFER_SIZE + 1;
      map_size = max(initial_map_size(), num_nodes + 2);
      //  begin and last will be allocate more memory
      //  to save time for inserting elements in deque.
      map = map_allocator.allocate(map_size);
      //  set start and finish node in the middle of map.
      map_pointer nstart = map + (map_size - num_nodes) / 2;
      map_pointer nfinish = nstart + num_nodes - 1;
      for (map_pointer cur = nstart; cur <= nfinish; cur++) {
        *cur = allocate_node();
      }
      start.set_node(nstart);
      finish.set_node(nfinish);
      start.cur = start.first;
      finish.cur = finish.first + num_elements % BUFFER_SIZE;
    }
    /**
     *  reallocate map to reallocate nodes for map.
     *  @param nodes_to_add The number of nodes to add.
     *  @param add_at_front Add front or add back.
     */
    void reallocate_map(size_type nodes_to_add, bool add_at_front) {
      size_type old_num_nodes = finish.node - start.node + 1;
      size_type new_num_nodes = old_num_nodes + nodes_to_add;
      map_pointer new_nstart;
      if (map_size > 2 * new_num_nodes) {
        //  to balance map size.
        //  just to avoid map size being off balance.
        new_nstart = map + (map_size - new_num_nodes) / 2 +
        (add_at_front ? nodes_to_add : 0);
        if (new_nstart < start.node)
          copy(start.node, finish.node + 1, new_nstart);
        else
          copy_backward(start.node, finish.node + 1, new_nstart + old_num_nodes);
      } else {
        size_type new_map_size = map_size + max(map_size, nodes_to_add) + 2;
        //  allocate new memory for new map.
        map_pointer new_map = map_allocator.allocate(new_map_size);
        new_nstart = new_map + (new_map_size - new_num_nodes) / 2 +
        (add_at_front ? nodes_to_add : 0);
        //  copy original map.
        copy(start.node, finish.node + 1, new_nstart);
        //  reallocate original map.
        map_allocator.deallocate(map, map_size);
        //  set new map and corresponding size.
        map = new_map;
        map_size = new_map_size;
      }
      //  reset start and finish node.
      start.set_node(new_nstart);
      finish.set_node(new_nstart + old_num_nodes - 1);
    }

  protected:
    iterator start;
    iterator finish;
    map_pointer map;
    size_type map_size;

  public:
    /**
     *  default constructor
     */
    deque() : start(), finish(), map(0) { create_map_and_nodes(0); }
    /**
     *  deconstructor
     */
    ~deque() {
      for (map_pointer node = start.node; node <= finish.node; ++node) {
        //  free memory of buffer.
        delete *node;
      }
      destroy_map_and_nodes();
    }
    /**
     *  reallocate map memory.
     */
    void destroy_map_and_nodes() { map_allocator.deallocate(map, map_size); }

    iterator begin() { return start; }
    iterator end() { return finish; }
    reference front() { return *start; }
    reference back() {
      iterator temp = finish;
      --temp;
      return *temp;
    }
    /**
     *  random access to get reference of element.
     *  @param n steps
     *  @return reference of elements.
     */
    reference operator[](size_type n) { return start[difference_type(n)]; }
    size_type size() const { return finish - start; }
    bool empty() const { return finish == start; }
    /**
     *  insert value in the back of deque.
     *  @param t value.
     */
    void push_back(const value_type& t) {
      //  check if there is the enough memory to insert element
      if (finish.cur != finish.last - 1) {
        data_allocator.construct(finish.cur, t);
        //  directly constructor.
        ++finish.cur;
        //  adjust the finish map iterator.
      } else {
        //  the special push back version.
        push_back_aux(t);
      }
    }
    /**
     *  the speacial version of push_back.
     *  @param t value.
     */
    void push_back_aux(const value_type& t) {
      value_type t_copy = t;
      reserve_map_at_back();
      *(finish.node + 1) = allocate_node();
      //  allocate new node buffer.
      map_allocator.construct(finish.cur, t_copy);
      //  constructe.
      finish.set_node(finish.node + 1);
      //  change finish iterator to point to new node.
      finish.cur = finish.first;
      //  set finish state.
    }
    /**
     *  reserve map at back.
     *  @param nodes_to_add the number of nodes to add.
     */
    void reserve_map_at_back(size_type nodes_to_add = 1) {
      if (nodes_to_add > map_size - (finish.node - map) - 1)
        //  if the size of back deque
        //  reallocate map at back.
        reallocate_map(nodes_to_add, false);
    }
    /**
     *  insert elements in the front of deque.
     *  @param t value.
     */
    void push_front(const value_type& t) {
      if (start.cur != start.first) {
        //  check if there is enough memory to allocate new element.
        data_allocator.construct(start.cur - 1, t);
        --start.cur;
      } else
        //  if there isn't enough memory to insert new element
        //  call the special push front version.
        push_front_aux(t);
    }
    /**
     *  the special version of push front.
     *  @param t value
     */
    void push_front_aux(const value_type& t) {
      value_type t_copy = t;
      reserve_map_at_front();
      *(start.node - 1) = allocate_node();
      start.set_node(start.node - 1);
      start.cur = start.last - 1;
      data_allocator.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);
    }
    /**
     *  erase the back element of the deque.
     */
    void pop_back() {
      if (!empty()) {
        if (finish.cur != finish.first) {
          data_allocator.destroy(finish.cur);
          --finish.cur;
        } else
          pop_back_aux();
      }
    }
    /**
     *  the special version of pop back.
     */
    void pop_back_aux() {
      deallocate_node(finish.first);  // reallocate tha last buffer.
      finish.set_node(finish.node - 1);
      finish.cur = finish.last - 1;
      data_allocator.destroy(finish.cur);  // deconstructor element
    }
    /**
     *  erase the front element
     */
    void pop_front() {
      if (!empty()) {
        if (start.cur != start.last - 1) {
          data_allocator.destroy(start.cur);
          ++start.cur;
        } else

          pop_front_aux();
      }
    }
    void pop_front_aux() {
      data_allocator.destroy(start.cur);
      deallocate_node(start.first);  //  free the first map iterator.
      start.set_node(start.node + 1);
      start.cur = start.first;
    }

    /**
     *  random insert elements
     *  @param position iterator of random position.
     *  @param value
     *  @return iterator.
     */
    iterator insert(iterator position, const value_type& value = value_type()) {
      if (position == start) {
        push_front(value);
        return start;
      } else if (position == finish) {
        push_front(value);
        return finish;
      } else {
        return insert_aux(position, value);
      }
    }
    /**
     *  speacial version of insert

     *  @param pos random position.
     *  @param x   value
     *  @return iterator of new element
     */
    iterator 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;
    }
    /**
     *  erase elements at random position.
     *  @param pos position
     *  @return the next element's iterator.
     */
    iterator erase(iterator pos) {
      iterator next = pos;
      ++next;
      difference_type index = pos - start;
      //  check operate at which side will cost less price.
      if (index < (size() >> 1)) {
        copy_backward(start, pos, next);
        pop_front();
      } else {
        copy(next, finish, pos);
        pop_back();
      }
      return start + index;
    }
    /**
     *  erase elements at random position
     *  between first iterator and last iterator.
     *  @param first start position
     *  @param last  finish position
     *  @return the next element's iterator.
     */
    iterator erase(iterator first, iterator last) {
      if (first == start && last == finish) {
        //  if erasing the whole deque.
        //  just clear.
        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;  // 标记deque的新起点
          destroy(start, new_start);  // 移动完毕,将冗余的元素析构
          // 以下将冗余的缓冲区释放
          for (map_pointer cur = start.node; cur < new_start.node; ++cur)
            data_allocator.deallocate(*cur, buffer_size());
          start = new_start;  // 设定deque的新起点
        } else                // 如果清除区间后方的元素个数比较少
        {
          copy(last, finish, first);  // 向前移动后方元素(覆盖清除区间)
          iterator new_finish = finish - n;  // 标记deque的新尾点
          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;  // 设定deque的新尾点
        }
        return start + elems_before;
      }
    }
    /**
     *  clear every element in the deque.
     */
    void clear() {
      // 以下针对头尾以外的每一个缓冲区
      for (map_pointer node = start.node + 1; node < finish.node; ++node) {
        // 将缓冲区内的所有元素析构
        for (int i = 0; i != buffer_size() + 1; i++) {
          data_allocator.destroy(*node + i);
        }
        // 释放缓冲区内存
        data_allocator.deallocate(*node, buffer_size());
      }

      if (start.node != finish.node)  // 至少有头尾两个缓冲区
      {
        for (auto iter = start.cur; iter != start.last; iter++) {
          data_allocator.destroy(iter);
        }
        for (auto iter = finish.first; iter != finish.cur; iter++) {
          data_allocator.destroy(iter);
        }
        // 以下释放尾缓冲区。注意:头缓冲区保留
        data_allocator.deallocate(finish.first, buffer_size());
      } else  // 只有一个缓冲区
        for (auto iter = start.cur; iter != finish.cur; iter++) {
          data_allocator.destroy(iter);  // 将此唯一缓冲区内的所有元素析构
        }
      // 注意:并不释放缓冲区空间,这唯一的缓冲区将保留
      finish = start;  // 调整状态
    }
  };
#endif /* Deque_h */
}

测试文件:(gtest)

#include <iostream>
#include "gtest/gtest.h"
#include <deque>
#include "Deque.h"
using namespace std;
deque<int> deq_standard;
Deque::deque<int> deq_test;

TEST(TestOperation, Test_push_back) {
  int n;
  cout << "input a random number" << endl;
  cin >> n;
  for (int i = 0; i != n; i++) {
    deq_standard.push_back(i);
    deq_test.push_back(i);
  }
  EXPECT_EQ(deq_standard, deq_test);
}
TEST(TestOperation, Test_push_front) {
  int n;
  cout << "input a random number" << endl;
  cin >> n;
  for (int i = 0; i != n; i++) {
    deq_standard.push_front(i);
    deq_test.push_front(i);
  }
  EXPECT_EQ(deq_standard, deq_test);
}

TEST(TestOperation, Test_insert) {
  deq_test.insert(deq_test.begin(), 3);
  deq_standard.insert(deq_standard.begin(), 3);
  deq_test.insert(deq_test.end(), 4);
  deq_standard.insert(deq_standard.end(), 4);
  Deque::deque<int>::iterator iter_t = deq_test.begin();
  deque<int>::iterator iter_s = deq_standard.begin();
  iter_t += 3;
  iter_s += 3;
  deq_test.insert(iter_t, 10);
  deq_standard.insert(iter_s, 10);
  EXPECT_EQ(deq_standard, deq_test);
}
TEST(TestOperation, Test_erase) {
  Deque::deque<int>::iterator iter_t = deq_test.begin();
  deque<int>::iterator iter_s = deq_standard.begin();
  iter_t += 6;
  iter_s += 6;
  deq_test.erase(iter_t);
  deq_standard.erase(iter_s);
  EXPECT_EQ(deq_standard, deq_test);
}
TEST(TestOperation, Test_clear) {
  deq_standard.clear();
  deq_test.clear();
  EXPECT_EQ(deq_standard, deq_test);
}
TEST(Test_all, test_all) {
  int m, n;
  cout << "input two random number" << endl;
  cin >> m >> n;
  for (int i = 0; i < m; i++) {
    deq_standard.push_front(i);
    deq_test.push_front(i);
  }

  EXPECT_EQ(deq_standard, deq_test);
  EXPECT_EQ(deq_standard.size(), deq_test.size());
  EXPECT_EQ(deq_standard[0], deq_test[0]);
  deque<int>::iterator tmp1 = deq_standard.begin();
  deque<int>::iterator tmp2 = tmp1;
  Deque::deque<int>::iterator tmp1_t = deq_test.begin();
  Deque::deque<int>::iterator tmp2_t = tmp1_t;

  tmp2 = tmp2 + 5;
  tmp2_t = tmp2_t + 5;
  EXPECT_EQ(*(tmp2++), *(tmp2_t++));

  ++tmp2;
  ++tmp2_t;
  EXPECT_EQ(*(tmp2++), *(tmp2_t++));

  tmp2 = tmp2 - 2;
  tmp2_t = tmp2_t - 2;
  EXPECT_EQ(*(tmp2++), *(tmp2_t++));
  tmp2 += 25;
  tmp2_t += 25;
  EXPECT_EQ(*(tmp2--), *(tmp2_t--));

  --tmp2;
  tmp2 -= 13;
  --tmp2_t;
  tmp2_t -= 13;

  EXPECT_EQ(*tmp2, *tmp2_t);
  EXPECT_EQ(tmp1[0], tmp1_t[0]);
  EXPECT_EQ(tmp1[8], tmp1_t[8]);
  EXPECT_EQ(tmp1[23], tmp1_t[23]);
  EXPECT_EQ(tmp2[-3], tmp2_t[-3]);
}

int main(int argc, char **argv) {
    printf("Running main() from gtest_main.cc\\n");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

测试

用valgrind测试内存和gtest进行单元测试。

这里写图片描述

以上是关于[C++]Deque with iterator实现细节的主要内容,如果未能解决你的问题,请参考以下文章

C++迭代器失效的几种情况总结

STL deque

C++ STL partial_sort

Iterator::collect 是不是分配与 String::with_capacity 相同的内存量?

C++中,为啥函数参数不够也可以调用?而且函数模板定义中没有提供默认值。

C++ template技巧性基础知识总结