STL淺析——序列式容器vector的元素操作: pop_back()、ease()、clear() 和 insert()


  vector 容器的元素操作函數有很多,我就選取四個講解一下,首先是pop_back()函數,pop() 函數的作用是將尾端元素拿掉並調整大小,並不涉及到容量的改變:

  void pop_back()
{
--_M_finish;  //_M_finish是指向現有元素的最后一個元素的下一個cell地址,只需要減一,然后調用destory()即可 destroy(_M_finish); }

  ease() 函數作用是清除某一個元素,或者清除兩個迭代器之間的所有元素,如下:

//清除某一個元素
  iterator erase(iterator __position) 
  {
    if (__position + 1 != end())
      copy(__position + 1, _M_finish, __position);
    --_M_finish;
    destroy(_M_finish);
    return __position;
  }
  //清除迭代器__first 和 __last之間的所有元素
  iterator erase(iterator __first, iterator __last)
  {
    iterator __i = copy(__last, _M_finish, __first);  //將__last到_M_finish(最后一個元素的下一個cell)所有元素copy到從__first開始的地方
                                 //返回_M_finish對應的cell,在copy之后所在位置的迭代器,賦值給__i
   //然后銷毀從__i到_M_finish的所有元素,並移動
_M_finish到刪除元素之后新元素序列的尾端的下一個cell
  destroy(__i, _M_finish); _M_finish = _M_finish - (__last - __first); return __first;
}

  第二個 erase 示意圖如下:

  

  

  insert函數是把元素插入到對應位置,該函數效率很低,特別是front插入,要移動所有元素退后一個位置,很花銷時間,企業級數據盡量少用 vector 的 insert,以下是其源代碼:

  

template <class _Tp, class _Alloc>
void vector<_Tp, _Alloc>::_M_fill_insert(iterator __position, size_type __n, 
                                            const _Tp& __x)
{
    if (__n != 0) //防止不插入元素而造成資源耗費
    {
        //備用空間大小大於或者等於新增元素個數
        if (size_type(_M_end_of_storage - _M_finish) >= __n) 
        {
            _Tp __x_copy = __x;
            //
            const size_type __elems_after = _M_finish - __position;
            iterator __old_finish = _M_finish;
       //我的技術太渣,理解倒是理解了,就是不知道為啥這么寫。。。。
if (__elems_after > __n) { uninitialized_copy(_M_finish - __n, _M_finish, _M_finish); _M_finish += __n; copy_backward(__position, __old_finish - __n, __old_finish); fill(__position, __position + __n, __x_copy); } else { uninitialized_fill_n(_M_finish, __n - __elems_after, __x_copy); _M_finish += __n - __elems_after; uninitialized_copy(__position, __old_finish, _M_finish); _M_finish += __elems_after; fill(__position, __old_finish, __x_copy); } //不明白為什么要比較__elems_after 和 _n,不是能夠全體移動並且直接插入要插入的元素嗎?所以
//感覺特別復雜,個人覺得可以改成: uninitialized_copy(__position, _M_finish, __position + n); _M_finish += __n; fill(__position, __position + __n, __x_copy); } else { //備用空間大小小於新增元素個數,必須配置額外內存,那就用到空間是配置器了 const size_type __old_size = size(); //決定新的長度,為舊的長度的兩倍,或者舊的長度+新的長度 const size_type __len = __old_size + max(__old_size, __n); //開始調用空間配置器 iterator __new_start = _M_allocate(__len); iterator __new_finish = __new_start; __STL_TRY { //移動元素 //首先移動要插入點位置之前的所有元素到新的vector __new_finish = uninitialized_copy(_M_start, __position, __new_start); //其次開始構造要插入的元素 __new_finish = uninitialized_fill_n(__new_finish, __n, __x); //最后移動要插入點位置之后的所有元素到新的vector __new_finish = uninitialized_copy(__position, _M_finish, __new_finish); } __STL_UNWIND((destroy(__new_start,__new_finish); //以下清除並且釋放舊的vector _M_deallocate(__new_start,__len))); destroy(_M_start, _M_finish); _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; } } }

  紅代碼部分如果if成立,則如下圖,侯捷大神《STL源碼解析》上的該圖很單調,本人太挫有點看不懂:

  

 

  如果if不成立,則如下圖:

  如果調用insert函數時空間不夠,如下:

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM