1. 程式人生 > >STL原始碼分析之deque 下

STL原始碼分析之deque 下

前言

前面兩節對deque基本所有的操作都分析了, 本節就分析deque的insert操作的實現. insert的過載函式有很多, 所以沒有在上節一起分析, 本節也只是對部分過載函式進行分析, 剩下的列出原始碼就行了.

原始碼分析

insert實現

這裡先將insert的所有過載函式進行羅列.

iterator insert(iterator position, const value_type& x);
iterator insert(iterator position) ;

// 呼叫相同的過載函式
void insert(iterator pos, size_type n,
const value_type& x); void insert(iterator pos, int n, const value_type& x); void insert(iterator pos, long n, const value_type& x); void insert(iterator pos, InputIterator first, InputIterator last); void insert(iterator pos, const value_type* first, const value_type* last); void insert
(iterator pos, const_iterator first, const_iterator last); void insert(iterator pos, InputIterator first, InputIterator last, input_iterator_tag); void insert(iterator pos, ForwardIterator first, ForwardIterator last,forward_iterator_tag);

iterator insert(iterator position, const value_type& x)

template <class T, class Alloc = alloc, size_t BufSiz = 0> 
class deque {
    ...
public:                         // Insert
  iterator insert(iterator position, const value_type& x) {
      // 如果只是在頭尾插入, 直接呼叫push就行了.
    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);
    }
  }
};

**insert(iterator pos, size_type n, const value_type& x) ** 在指定的位置插入n個元素並初始化.

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert(iterator pos, size_type n, const value_type& x) 
{
    // 同樣判斷是不是直接在頭尾進行插入.
  if (pos.cur == start.cur) {
      // 判斷還有沒有足夠的空間
    iterator new_start = reserve_elements_at_front(n);
    uninitialized_fill(new_start, start, x); // 範圍初始化
    start = new_start;	// 修改start位置
  }
  else if (pos.cur == finish.cur) {
    iterator new_finish = reserve_elements_at_back(n);	// 判斷還有沒有足夠的空間
    uninitialized_fill(finish, new_finish, x);	// 範圍初始化
    finish = new_finish;	// 修改finish位置
  }	
    // 隨機插入
  else 
    insert_aux(pos, n, 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 insert(iterator pos, InputIterator first, InputIterator last) **. 通過引數的型別選擇最優, 高效率的插入方式.

template <class InputIterator>
void insert(iterator pos, InputIterator first, InputIterator last) 
{
    insert(pos, first, last, iterator_category(first));
}

// input_iterator_tag型別的迭代器
template <class T, class Alloc, size_t BufSize>
template <class InputIterator>
void deque<T, Alloc, BufSize>::insert(iterator pos,InputIterator first, InputIterator last,
input_iterator_tag) 
{
  copy(first, last, inserter(*this, pos));	// 直接呼叫copy函式
}

// forward_iterator_tag型別的迭代器
template <class T, class Alloc, size_t BufSize>
template <class ForwardIterator>
void deque<T, Alloc, BufSize>::insert(iterator pos,ForwardIterator first,ForwardIterator last,forward_iterator_tag) 
{
  size_type n = 0;
  distance(first, last, n); // 計算迭代器之間的距離
    // 同樣, 首尾插入判斷
  if (pos.cur == start.cur) {
    iterator new_start = reserve_elements_at_front(n);
    __STL_TRY {
      uninitialized_copy(first, last, new_start);
      start = new_start;
    }
    __STL_UNWIND(destroy_nodes_at_front(new_start));
  }
  else if (pos.cur == finish.cur) {
    iterator new_finish = reserve_elements_at_back(n);
    __STL_TRY {
      uninitialized_copy(first, last, finish);
      finish = new_finish;
    }
    __STL_UNWIND(destroy_nodes_at_back(new_finish));
  }
    // 隨機插入
  else
    insert_aux(pos, first, last, n);
}
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert(iterator pos,const value_type* first,const value_type* last) 
{
  size_type n = last - first;
  if (pos.cur == start.cur) {
    iterator new_start = reserve_elements_at_front(n);
    __STL_TRY {
      uninitialized_copy(first, last, new_start);
      start = new_start;
    }
    __STL_UNWIND(destroy_nodes_at_front(new_start));
  }
  else if (pos.cur == finish.cur) {
    iterator new_finish = reserve_elements_at_back(n);
    __STL_TRY {
      uninitialized_copy(first, last, finish);
      finish = new_finish;
    }
    __STL_UNWIND(destroy_nodes_at_back(new_finish));
  }
  else
    insert_aux(pos, first, last, n);
}

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert(iterator pos,const_iterator first,const_iterator last)
{
  size_type n = last - first;
  if (pos.cur == start.cur) {
    iterator new_start = reserve_elements_at_front(n);
    __STL_TRY {
      uninitialized_copy(first, last, new_start);
      start = new_start;
    }
    __STL_UNWIND(destroy_nodes_at_front(new_start));
  }
  else if (pos.cur == finish.cur) {
    iterator new_finish = reserve_elements_at_back(n);
    __STL_TRY {
      uninitialized_copy(first, last, finish);
      finish = new_finish;
    }
    __STL_UNWIND(destroy_nodes_at_back(new_finish));
  }
  else
    insert_aux(pos, first, last, n);
}

insert_auto

上面對insert函式做了簡單的分析, 可以發現基本每一個insert過載函式都會呼叫了insert_auto, 現在我們就來分析該函式的實現.

**insert_aux(iterator pos, const value_type& x) **.

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進行調整
    copy(front2, pos1, front1);
  }
    // 離尾近
  else {
    push_back(back());	// 將尾往前移動
      // 調整將要移動的距離
    iterator back1 = finish;
    --back1;
    iterator back2 = back1;
    --back2;
    pos = start + index;
      // 用copy進行調整
    copy_backward(pos, back2, back1);
  }
  *pos = x_copy;
  return pos;
}

**insert_aux(iterator pos, size_type n, const value_type& x) ** .

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert_aux(iterator pos, size_type n, const value_type& x) 
{
  const difference_type elems_before = pos - start;
  size_type length = size();
  value_type x_copy = x;
    // 判斷插入的位置離頭還是尾比較近
    // 離頭近
  if (elems_before < length / 2) {
    iterator new_start = reserve_elements_at_front(n);	// 新的記憶體空間
    iterator old_start = start;
      // 計算pos的新位置
    pos = start + elems_before;
    __STL_TRY {
        // 到頭的距離大於插入的個數n
      if (elems_before >= difference_type(n)) {
          // 一部分一部分的進行調整
        iterator start_n = start + difference_type(n);
        uninitialized_copy(start, start_n, new_start);
        start = new_start;
        copy(start_n, pos, old_start);
        fill(pos - difference_type(n), pos, x_copy);
      }
        // 到頭的距離不大於插入的個數n
      else {
        __uninitialized_copy_fill(start, pos, new_start, start, x_copy);
        start = new_start;
        fill(old_start, pos, x_copy);
      }
    }
    __STL_UNWIND(destroy_nodes_at_front(new_start));
  }
    // 離尾近. 執行都是一樣的
  else {
    iterator new_finish = reserve_elements_at_back(n);
    iterator old_finish = finish;
    const difference_type elems_after = difference_type(length) - elems_before;
    pos = finish - elems_after;
    __STL_TRY {
      if (elems_after > difference_type(n)) {
        iterator finish_n = finish - difference_type(n);
        uninitialized_copy(finish_n, finish, finish);
        finish = new_finish;
        copy_backward(pos, finish_n, old_finish);
        fill(pos, pos + difference_type(n), x_copy);
      }
      else {
        __uninitialized_fill_copy(finish, pos + difference_type(n),
                                  x_copy,
                                  pos, finish);
        finish = new_finish;
        fill(pos, old_finish, x_copy);
      }
    }
    __STL_UNWIND(destroy_nodes_at_back(new_finish));
  }
}

剩下的就不一一進行分析了, 基本要涉及到的操作前面都已經講的很明白了.

#ifdef __STL_MEMBER_TEMPLATES  
template <class T, class Alloc, size_t BufSize>
template <class ForwardIterator>
void deque<T, Alloc, BufSize>::insert_aux(iterator pos,
                                          ForwardIterator first,
                                          ForwardIterator last,
                                          size_type n)
{
  const difference_type elems_before = pos - start;
  size_type length = size();
  if (elems_before < length / 2) {
    iterator new_start = reserve_elements_at_front(n);
    iterator old_start = start;
    pos = start + elems_before;
    __STL_TRY {
      if (elems_before >= difference_type(n)) {
        iterator start_n = start + difference_type(n); 
        uninitialized_copy(start, start_n, new_start);
        start = new_start;
        copy(start_n, pos, old_start);
        copy(first, last, pos - difference_type(n));
      }
      else {
        ForwardIterator mid = first;
        advance(mid, difference_type(n) - elems_before);
        __uninitialized_copy_copy(start, pos, first, mid, new_start);
        start = new_start;
        copy(mid, last, old_start);
      }
    }
    __STL_UNWIND(destroy_nodes_at_front(new_start));
  }
  else {
    iterator new_finish = reserve_elements_at_back(n);
    iterator old_finish = finish;
    const difference_type elems_after = difference_type(length) - elems_before;
    pos = finish - elems_after;
    __STL_TRY {
      if (elems_after > difference_type(n)) {
        iterator finish_n = finish - difference_type(n);
        uninitialized_copy(finish_n, finish, finish);
        finish = new_finish;
        copy_backward(pos, finish_n, old_finish);
        copy(first, last, pos);
      }
      else {
        ForwardIterator mid = first;
        advance(mid, elems_after);
        __uninitialized_copy_copy(mid, last, pos, finish, finish);
        finish = new_finish;
        copy(first, mid, pos);
      }
    }
    __STL_UNWIND(destroy_nodes_at_back(new_finish));
  }
}

#else /* __STL_MEMBER_TEMPLATES */

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::insert_aux(iterator pos,
                                          const value_type* first,
                                          const value_type* last,
                                          size_type n)
{
  const difference_type elems_before = pos - start;
  size_type length = size();
  if (elems_before < length / 2) {
    iterator new_start = reserve_elements_at_front(n);
    iterator old_start = start;
    pos = start + elems_before;
    __STL_TRY {
      if (elems_before >= difference_type(n)) {
        iterator start_n = start + difference_type(n);
        uninitialized_copy(start, start_n, new_start);
        start = new_start;
        copy(start_n, pos, old_start);
        copy(first, last, pos - difference_type(n));
      }
      else {
        const value_type* mid = first + (difference_type(n) - elems_before);
        __uninitialized_copy_copy(start, pos, first, mid, new_start);
        start = new_start;
        copy(mid, last, old_start);
      }
    }
    __STL_UNWIND(destroy_nodes_at_front(new_start));
  }
  else {
    iterator new_finish = reserve_elements_at_back(n);
    iterator old_finish = finish;
    const difference_type elems_after = difference_type(length) - elems_before;
    pos = finish - elems_after;
    __STL_TRY {
      if (elems_after > difference_type(n)) {
        iterator finish_n = finish - difference_type(n);
        uninitialized_copy(finish_n, finish, finish);
        finish = new_finish;
        copy_backward(pos, finish_n, old_finish);
        copy(first, last, pos);
      }
      else {
        const value_type* mid = first + elems_after;
        __uninitialized_copy_copy(mid, last, pos, finish, finish);
        finish = new_finish;
        copy(first, mid, pos);
      }
    }
    __STL_UNWIND(destroy_nodes_at_back(new_finish)
            
           

相關推薦

STL原始碼分析deque

前言 前面兩節對deque基本所有的操作都分析了, 本節就分析deque的insert操作的實現. insert的過載函式有很多, 所以沒有在上節一起分析, 本節也只是對部分過載函式進行分析, 剩下的列出原始碼就行了. 原始碼分析 insert實現 這裡先將insert的

STL原始碼分析deque有序容器 中

前言 前一節我們分析了deque的基本使用, 本節我們來分析一下deque的對map的操作, 即插入, 刪除等. 但是本節只分析push, pop和刪除操作, 而insert操作有點複雜還是放到下節來分析. push, pop 因為deque的是能夠雙向操作, 所以其push

STL原始碼分析deque有序容器 上

前言 deque的功能很強大, 其複雜度也比list, vector複雜很多. deque是一個random_access_iterator_tag型別. 前面分析過vector是儲存在連續的線性空間, 頭插入和刪除其代價都很大, 當陣列滿了還要重新尋找更大的空間; deque也是一

STL原始碼分析slist有序容器

前言 上節我們對slist的基本構成, 構造析構做了分析, 本節 我們就來分析關於slist的基本元素操作. slist分析 基本屬性資訊 slist是隻有正向迭代, 所以只能直接獲取頭部的資料. template <class T, class Alloc =

STL原始碼分析list有序容器

前言 前兩節對list的push, pop, insert等操作做了分析, 本節準備探討list怎麼實現sort功能. list是一個迴圈雙向連結串列, 不是一個連續地址空間, 所以sort功能需要特殊的演算法單獨實現, 而不能用演算法中的sort. 當然還可以將list的元素插

STL原始碼分析__type_traits型別

前言 上一篇探討的是traits是為了將迭代器沒能完善的原生指標, traits用特化和偏特化程式設計來完善. 這一篇準備探討__type_traits, 為了將我們在空間配置器裡面的提過的__true_type和false_type進行解答. 而type_traits型別對我們ST

STL原始碼分析traits萃取劑

前言 前面我們分析了迭代器的五類, 而迭代器所指向物件的型別被稱為value type. 傳入引數的型別可以通過編譯器自行推斷出來, 但是如果是函式的返回值的話, 就無法通過value type讓編譯器自行推斷出來了. 而traits就解決了函式返回值型別. 同樣原生指標不能內嵌型別

STL原始碼分析迭代器

前言 迭代器是將演算法和容器兩個獨立的泛型進行調和的一個介面. 使我們不需要關係中間的轉化是怎麼樣的就都能直接使用迭代器進行資料訪問. 而迭代器最重要的就是對operator *和operator->進行過載, 使它表現的像一個指標. 型別 迭代器根據移動特性和實施操作

STL原始碼分析記憶體池

前言 上一節只分析了第二級配置器是由多個連結串列來存放相同記憶體大小, 當沒有空間的時候就向記憶體池索取就行了, 卻沒有具體分析記憶體池是怎麼儲存空間的, 是不是記憶體池真的有用不完的記憶體, 本節我們就具體來分析一下 記憶體池 static data template的初始

STL原始碼分析第二級配置器

前言 第一級是直接呼叫malloc分配空間, 呼叫free釋放空間, 第二級三就是建立一個記憶體池, 小於128位元組的申請都直接在記憶體池申請, 不直接呼叫malloc和free. 本節分析第二級空間配置器, STL將第二級配置器設定為預設的配置器, 所以只要一次申請的空間不超過1

STL原始碼分析第一級配置器

前言 上一節我們分析了空間配置器對new的配置, 而STL將空間配置器分為了兩級, 第一級是直接呼叫malloc分配空間, 呼叫free釋放空間, 第二級三就是建立一個記憶體池, 小於128位元組的申請都直接在記憶體池申請, 不直接呼叫malloc和free. 本節我們就先分析第

STL原始碼分析空間配置器

前言 SGI STL將new的申請空間和呼叫建構函式的兩個功能分開實現, 如果對new不太清楚的, 可以先去看看這一篇new實現再來看配置器也不遲. 本節是STL分析的第一篇, 主要分析STL各個部分都會出現的alloc實現, 雖然每個部分都只會預設呼叫它, 不瞭解它也可以看懂分析,

STL原始碼分析hashtable關聯容器 上

前言 前面我們分析過RB-tree關聯容器, RB-tree在插入(可重複和不可重複), 刪除等操作時間複雜度都是O(nlngn), 以及滿足5個規則, 以及以他為底層的配接器; 本節就來分析hashtable另個關聯容器, 他在插入, 刪除等操作都可以做到O(1)的時間複雜度.

STL原始碼分析multimap配接器

前言 前面我們分析了map, 知道map是不允許插入相同的鍵值的, 也不會儲存第二次的資料, 而本節分析的multimap與map不同, 它允許多個重複的鍵值插入. mutimap操作 int main() { multimap<string, int> mul

STL原始碼分析multiset配接器

前言 前面也分析過set, 並且set不能插入相同的鍵, 本節分析的multiset與set不同之處就是他允許插入相同的鍵. multiset操作 int main() { multiset<string> multi; // 允許重複插入鍵 mult

STL原始碼分析map配接器

前言 上一節分析了pair結構, 正是為map分析做鋪墊, map本身實現也不難, 其資料儲存是pair, 儲存結構是RB-tree, 即map也並不能說是關聯容器, 而應該是配接器. map操作 map的insert必須是以pair為儲存結構, 當然也可以直接使用make_

STL原始碼分析pair結構體

前言 前面在分析set, RB-tree都有在insert實現中出現pair, 下節分析map的時候更會經常出現pair, 所以打算在之前先對pair有個認識. pair是一個有兩個變數的結構體, 即誰都可以直接呼叫它的變數, 畢竟struct預設許可權都是public, 將兩個

STL原始碼分析set配接器

前言 上面兩節我們分析了RB-tree, 同時我們也知道了rb-tree的插入操作還分為可重複插入和不可重複插入(insert_unique). 本節分析set, 嚴格意義說set就是修改了底層容器介面的, 所以應該是配置器. set就是將RB-tree作為底層容器, 以insert

STL原始碼分析RB-tree關聯容器 上

前言 本節將分析STL中難度很高的RB-tree, 如果對紅黑樹有所認識的那麼分析起來的難度也就不是很大, 對紅黑樹沒有太多瞭解的直接來分析的難度就非常的大了, 可以對紅黑樹有個瞭解紅黑樹之原理和演算法詳細介紹. 紅黑樹是很類似與AVL-tree的, 但是因為AVL-tree在插入,

STL原始碼分析slist有序容器 上

前言 不同於list是Forward Iterator型別的雙向連結串列, slist是單向連結串列, 也是Bidirectional Iterator型別. slist主要耗費的空間小, 操作一些特定的操作更加的快, 同樣類似與slist, 在執行插入和刪除操作迭代器都不會像vec