《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相关部分

相关文章
相关标签/搜索