C++ Standard Stl — SGI STL源碼學習筆記(05) stl_vector 與 一些問題的細化 1C++ Standard Stl — SGI STL源碼

來源:互聯網
上載者:User

  上篇文章中很粗略的角度講解了一下stl_deque的設計思想,以及涉及到得淺顯的STL記憶體管理方面,至少我們看得到的冰山一角.

  這篇文章中關於vector的分析,我將將一些問題細化一下,對一些函數做細緻的分析.有些時候,有些問題還是說清楚比較好.

 

 

  開啟stl_vector的源碼,發現vector的設計思路和stl_deque如出一轍,想想這樣是很合理的,保持實現的一致性.只是stl_vector沒有提供一個確定的

模板類Iterator去實現迭代器,而是在vector模板類中實現了迭代. 但是和deque基本沒有什麼大的不同.下面來看看源碼:

  

  1. 這次就不講解設計部分了,主要講解實現部分.如果沒有看前面一篇文章,我儘力做到和前一篇文章沒有關係,但是最好還是去瞭解一下設計部分.詳細

    可參考這篇文章:C++ Standard Stl -- SGI STL源碼學習筆記(04) stl_deque && 初涉STL記憶體管理.

 

  2. vector的記憶體系統管理範本類:_Vector_alloc_base. 它是一個模板類,但是有一個特化的版本,區別在於對分配器Allocator(不知道這種分配器的叫法

    是否合適,以前閱讀apache源碼分析的時候,裡面對於allocator稱作分配子,但是這兩者的作用和概念都是不同的.)對象是否為成員變數.

    好吧,對於通用_Vector_alloc_base模板類和特化_Vector_alloc_base模板類,我們從記憶體操作的方法上面區分一下:

    通用_Vector_alloc_base模板記憶體操作方法: 

  _Tp* _M_allocate(size_t __n)              // 使用成員變數實現記憶體操作      { return _M_data_allocator.allocate(__n); }  void _M_deallocate(_Tp* __p, size_t __n)    { if (__p) _M_data_allocator.deallocate(__p, __n); }

     特化_Vector_alloc_base記憶體操作方法:

  typedef typename _Alloc_traits<_Tp, _Allocator>::_Alloc_type _Alloc_type;  // 使用方法直接操作,沒有作為成員變數  _Tp* _M_allocate(size_t __n)    { return _Alloc_type::allocate(__n); }  void _M_deallocate(_Tp* __p, size_t __n)    { _Alloc_type::deallocate(__p, __n);}

     當然,無論是通用模板類還是特化模板類,都使用了traits技術.

  3. vector的成員變數:   

  _Tp* _M_start;      // start  _Tp* _M_finish;      // 初始化的時候_M_finish = _M_start  _Tp* _M_end_of_storage  // 指向最後一個元素的下一個位置. 注意不是最後一個元素.

    這三個成員變數都是vector繼承自基類, 這三個指標指向三個不同的位置. 可以從建構函式中看得到:    

_Vector_base(size_t __n, const _Alloc&)    : _M_start(0), _M_finish(0), _M_end_of_storage(0)   {    _M_start = _M_allocate(__n);    _M_finish = _M_start;    _M_end_of_storage = _M_start + __n;  }

    根據初始化的長度_n初始化_M_start, _M_finish, _M_end_of_storage.  

  explicit vector(const allocator_type& __a = allocator_type())    : _Base(__a) {}  vector(size_type __n, const _Tp& __value,         const allocator_type& __a = allocator_type())     : _Base(__n, __a)    { _M_finish = uninitialized_fill_n(_M_start, __n, __value); }  explicit vector(size_type __n)    : _Base(__n, allocator_type())    { _M_finish = uninitialized_fill_n(_M_start, __n, _Tp()); }  vector(const vector<_Tp, _Alloc>& __x)     : _Base(__x.size(), __x.get_allocator())    { _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); }

   由vector提供的建構函式可以看得出,都是使用基類_vector_base的建構函式進行初始化.由於vector模板類提供了一個預設參數,可以使用預設

   分配器allocator.

inline T* allocate(ptrdiff_t size, T*) {    set_new_handler(0);    T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));    if (tmp == 0) {cerr << "out of memory" << endl; exit(1);    }    return tmp;}

   初始化後M_start得到了allocate函數的返回指標,而M_finish預設初始化和M_start相同.看看對於_M_finish的處理.

   由宏uninitialized_fill_n處理,進行跳轉,到__uninitialized_fill_n,再到__uninitialized_fill_n_aux.

   SGI STL在這裡做了相當複雜的處理,主要是判斷vector裡面的元素類型判斷,是POD類型還是不是POD類型.(POD? Plain Old Data,樸素的舊式資料,built-in類型就是POD

   可以參開<<c++必知必會>> 條款11 編譯期會在類中放東西. 其中講到了類多態中的v-table,考慮是不是寫一篇隨筆介紹一下.)

template <class _ForwardIter, class _Size, class _Tp, class _Tp1>inline _ForwardIter __uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x, _Tp1*){  typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD;  return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD());}

  _type_traits模板類提供了很多偏特化,都是處理這種build-in類型. 對於build-in POD is_POD_type都是_true_type.

template <class _ForwardIter, class _Size, class _Tp>inline _ForwardIter__uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,                           const _Tp& __x, __true_type){  return fill_n(__first, __n, __x);}template <class _ForwardIter, class _Size, class _Tp>_ForwardIter__uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,                           const _Tp& __x, __false_type){  _ForwardIter __cur = __first;  __STL_TRY {    for ( ; __n > 0; --__n, ++__cur)      _Construct(&*__cur, __x);    return __cur;  }  __STL_UNWIND(_Destroy(__first, __cur));}

  這裡是對_M_finish的最終實現.補充fill_n的源碼: 

template <class _OutputIter, class _Size, class _Tp>_OutputIter fill_n(_OutputIter __first, _Size __n, const _Tp& __value) {  __STL_REQUIRES(_OutputIter, _OutputIterator);  for ( ; __n > 0; --__n, ++__first)    *__first = __value;  return __first;}

  不管vector中的元素類型是否是POD,都是移動_M_start,而且還做了相應的初始化.

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.