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