《STL源碼剖析》——List

List

list位於頭文件<<stl_list.h>>中node

list是sequence containers中的一種c++

1 List的基本架構

list的基本結構的UML關係圖以下:架構

須要注意的是,向list中insert元素時,會構造一個真正的_List_node<_Tp>類型的_Node,將這個插入list當中;也就是說_List_node<_Tp>纔是list中的真正元素函數

2 _List_iterator

2.1 _List_iterator的自增與自減

因爲list的中的_list_node並不保證在內存空間中必定是連續的,因此list的迭代器並不能像vector之類的同樣實現++或者- - 的操做,list的迭代器必須在++(或者 - -)時,必須正確的找到list中當前node的下一個位置(或者上一個位置)this

_List_iterator的自增與自減函數源碼以下:設計

_Self&
   operator++() _GLIBCXX_NOEXCEPT
   {
       _M_node = _M_node->_M_next;
       return *this;
   }
   
   _Self
   operator++(int) _GLIBCXX_NOEXCEPT
   {
       _Self __tmp = *this;
       _M_node = _M_node->_M_next;
       return __tmp;
   }
   
   _Self&
   operator--() _GLIBCXX_NOEXCEPT
   {
       _M_node = _M_node->_M_prev;
       return *this;
   }
   
   _Self
   operator--(int) _GLIBCXX_NOEXCEPT
   {
       _Self __tmp = *this;
       _M_node = _M_node->_M_prev;
       return __tmp;
   }

能夠看到,在++的重載中,都是經過_list_iterator中所存儲_M_node來獲取下一個_list_node的位置的(- -操做同理)指針

須要注意的是,list的iterator中指針_M_node的類型_List_node_base類型的,也就是說:在涉及到存取list節點中的數據時,須要向下轉型爲_List_node類型code

3 List的環狀結構

list其實不單單是一個雙向鏈表,更是一個環形雙向鏈表,list中有一個_List_node_header類型的啞頭節點,以下圖所示內存

list的end()即是指向這個啞頭節點的,begin()則是這個啞頭節點的下一個節點源碼

4 List中實用函數

如下的函數都位於gcc/libstdc++-v3/src/c++98/list.cc

4.1 _M_hook

在insert的過程中就用到了這個函數,用來將新的節點鏈入到指定位置以前並保持list的完整性

該函數源碼以下:

void
    _List_node_base::
    _M_hook(_List_node_base* const __position) _GLIBCXX_USE_NOEXCEPT
    {
      this->_M_next = __position;
      this->_M_prev = __position->_M_prev;
      __position->_M_prev->_M_next = this;
      __position->_M_prev = this;
    }

4. 2 _M_unhook

顧名思義,該函數的做用是將某個節點從鏈表中卸下

源碼以下:

void
    _List_node_base::_M_unhook() _GLIBCXX_USE_NOEXCEPT
    {
      _List_node_base* const __next_node = this->_M_next;
      _List_node_base* const __prev_node = this->_M_prev;
      __prev_node->_M_next = __next_node;
      __next_node->_M_prev = __prev_node;
    }

4.3 _M_transfer

該函數的做用是將[__first, __last)之間的節點移動到另外一個位置

前半部分是調整_M_next指針

後半部分是調整_M_prev指針

該函數源碼以下:

void
    _List_node_base::
    _M_transfer(_List_node_base * const __first,
    _List_node_base * const __last) _GLIBCXX_USE_NOEXCEPT {
      if (this != __last) {
            // Remove [first, last) from its old position.
            __last->_M_prev->_M_next  = this;
            __first->_M_prev->_M_next = __last;
            this->_M_prev->_M_next    = __first;
    
            // Splice [first, last) into its new position.
            _List_node_base* const __tmp = this->_M_prev;
          this->_M_prev                = __last->_M_prev;
            __last->_M_prev              = __first->_M_prev;
            __first->_M_prev             = __tmp;
      }
    }

該函數是內部函數,不對外暴露,可是list不少對外暴露的函數內部實現也是利用了_M_transfer函數,好比:merge

4.4 _M_reverse

該函數是對外暴露的reverse()函數的內部調用函數

void
    _List_node_base::_M_reverse() _GLIBCXX_USE_NOEXCEPT
    {
      _List_node_base* __tmp = this;
      do
        {
            std::swap(__tmp->_M_next, __tmp->_M_prev);
    
            // Old next node is now prev.
            __tmp = __tmp->_M_prev;
        } while (__tmp != this);
    }

5 forward_list

< >是單向鏈表,其設計與list基本相同,只不過是單向的,大體結構與函數能夠參看list相關部分

相關文章
相關標籤/搜索