《STL源码剖析》——List

List

list位于头文件<<stl_list.h>>中

list是sequence containers中的一种

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的下一个位置(或者上一个位置)

_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类型

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

<<forward_list>>是单向链表,其设计与list基本相同,只不过是单向的,大致结构与函数可以参看list相关部分

posted @ 2019-11-11 23:00  cookcocck  阅读(422)  评论(0编辑  收藏  举报