C++ Standard Stl — SGI STL源碼學習筆記(06) stl_vector 與 一些問題的細化 2 push_back函數剖析

來源:互聯網
上載者:User

  上一篇文章中,關於stl_vector的故事只是個開始.  這篇文章中,接著去分析vector中的細節問題. 

 

  再次聲明,我沒有看過關於stl源碼分析方面的書籍,強調這一點是為了不會讓別人誤會我是從別的地方抄襲的. 另外,歡迎大家拍磚。

  後面陸續的幾篇文章都會詳細分析vector中的函數實現. 我盡量做到篇幅不大,而且能夠盡量用自己的語言和自己分析的結果給大

  家展現實現的過程. 這樣不會浪費大家的時間.寫的不好就請原諒了.

 

    push_back函數的作用就是從_M_finish指向的位置開始插入資料。如果預先分配的儲存單元不夠,則會做擴充處理.會在後面分析的時候

    說明這個問題.

  void push_back(const _Tp& __x) {    if (_M_finish != _M_end_of_storage) {      construct(_M_finish, __x);      ++_M_finish;    }    else      _M_insert_aux(end(), __x);  }// **// *  實現和上面相同,只是在需要初始化的地方都是用預設初始化值// **  void push_back() {    if (_M_finish != _M_end_of_storage) {      construct(_M_finish);      ++_M_finish;    }    else      _M_insert_aux(end());  }

       1. _M_finish和_M_end_of_storage有什麼區別?_M_finish和_M_end_of_storage同樣都是vector從vector_base中繼承來的,

    但是二者的作用是不同的.

      [ _M_finish ] :  資料類型的指標,執行當前操作的資料. 在預設的初始化時候,_M_finish==_M_start.也就是指向底層儲存元素

                 數組的頭元素.例如不斷的往裡面push_back資料,那麼_M_finish就會不斷的像數組的尾端移動,

               直到_M_end_of_storage.

      

 [_M_end_of_storage ] :  _M_end_of_storage在使用vector第一次初始化分配數組記憶體的時候,是指向數組的最後一個元素的後一個位置

               因為初始化的時候 _M_finish = _M_start, _M_end_of_storage = _M_start + _n. (_n是元素個數).

                 隨著不斷的對vector進行操作,後面可能會導致_M_end_of_storage發生變化.

 

    說的直白一點就是,_M_finish是_M_start(頭指標)和_M_end_of_storage(尾指標的後一個位置)之間遊動的遊標.

 

  2. 執行push_back(n)的操作的時候,首先會檢查數組的容量有沒有達到上限,如果_M_finish == _M_end_of_storage.那麼就需要擴大

    儲存單元,就會在_M_insert_aux(end(),_x)中進行容量的擴增.

 

  3. 如果沒有達到上限的話,也就是說有空餘的空間,那麼就給當前遊標_M_finish指向的位置賦值,然後將遊標向下一個位置移動.

   

  4. 如果沒有達到上限,就使用construct對_M_finish指向的記憶體地區進行賦值. 

template <class _T1, class _T2>inline void _Construct(_T1* __p, const _T2& __value) {  new ((void*) __p) _T1(__value);}

  對於new的這種用法,不是很常見,但是在<<c++ primer>>中後面"特殊工具與技術"章節有講解.

new (place_address) typenew (place_address) type(parm-list)

  5. 如果達到上限,就需要擴張儲存地區,按照原地區的2倍進行擴張.    

 const size_type __old_size = size();                         // 擷取原儲存地區長度    const size_type __len = __old_size != 0 ? 2 * __old_size : 1;         // 擴張為原來的2倍    iterator __new_start = _M_allocate(__len);                    // 按照新儲存長度重新申請記憶體    iterator __new_finish = __new_start;    __STL_TRY {      __new_finish = uninitialized_copy(_M_start, __position, __new_start);     // 將原來數組中的_M_start -> _M_finish之間的資料複製到新的儲存地區      construct(__new_finish, __x); // insert new value.                // 插入新資料,和前面的 操作一樣       ++__new_finish; // go next.                            // 移動_M_finish      __new_finish = uninitialized_copy(__position, _M_finish, __new_finish);         }    __STL_UNWIND((destroy(__new_start,__new_finish),                   _M_deallocate(__new_start,__len)));    destroy(begin(), end());    _M_deallocate(_M_start, _M_end_of_storage - _M_start);             // 釋放原儲存記憶體    _M_start = __new_start;                               // 處理其他改動    _M_finish = __new_finish;    _M_end_of_storage = __new_start + __len;

  這裡可能有些人不明白為什麼要調用兩次uninitialized_copy函數,其實有點想多了,這要看上面的調用:

    _M_insert_aux(end(), _x). 而end()的作用就是擷取_M_finish.而在uninitialized_copy函數中,首先會進行判斷.   

template <class _InputIter, class _ForwardIter>_ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,                         _ForwardIter __result,                         __false_type){  _ForwardIter __cur = __result;  __STL_TRY {    for ( ; __first != __last; ++__first, ++__cur)      _Construct(&*__cur, *__first);    return __cur;  }  __STL_UNWIND(_Destroy(__result, __cur));}

   雖然通過很多層的轉換,但是還是可以看到判斷_first != _last. 所以在上面的調用中這句是不會有執行的.而這看起來有點多此一舉是吧?

  不是. 因為_M_insert_aux提供的是通用的使用方法,需要使用一種通用的實現.而上面的調用最終還是會得到 _new_finish = _new_finish.

  所以不需要糾結.

  

  最後,關於push_back的另一個一個參數的版本就不需要多解釋了,因為二者之間在實現上方法和原理都是一樣的,多說無益.

    

    

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.