本部分的内容包括list的源码分析。
一、G2.9版本的list源码
list底层实现为双向循环链表,并且环状链表的尾端还有一个空白节点,代表尾后迭代器指向的节点,用以符合STL前闭后开的原则,其示意图如下:
G2.9版本的源码如下:
template <class T, class Alloc = alloc>
class list{
protected:
typedef __list_node<T> list_node;
public:
typedef list_node* link_type;
typedef __list_iterator<T, T&, T*> iterator;
protected:
link_type node;
.....
};
template <class T>
struct __list_node{
typedef void* void_pointer;
void_pointer prev;
void_pointer next;
T data;
};
template <class T, class Ref, class Ptr>
struct __list_iterator{
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
.....
};
1. 从源码可以看出,G2.9的list包含一个头指针,指向链表中的头结点,所以对list求sizeof的大小为4。
2. list的节点的类型为__list_node<T>,源码如上。其内的指针类型为void*,所以后续需要类型转换,G4.9对此做了修改。
二、list中的iterator的设计
迭代器比较重要,并且和后面一个部分密切相关,所以单独拿出来说一下。其源码如下:
template <class T, class Ref, class Ptr>
struct __list_iterator{
typedef __list_iterator<T, Ref, Ptr> self;
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef ptrdiff_t difference_type;
link_node node;
reference operator*() const { return (*node).data; }
pointer operator->() const { return &(operator*()); }
self& operator++()
{ node = (link_type)((*node).next); return *this; }
self operator++(int)
{ self tmp = *this; ++*this; return tmp; }
......
};
1. 可以看出迭代器包括一堆typedef和操作符重载(后面会讲几乎所有迭代器都一定要有这五个typedef)。
2. 注意++的前置版本和后置版本的区别,参数列表,返回类型等
3. 对于符号->的重载编译器有一些特殊处理(这里不太理解),如下图所示:
三、G4.9中的list
虽然也是双向循环链表,但是和G2.9的设计略有不同。一个list内包含一个_List_node_base<_Tp>,其内是两个指针prev和next,代表的是尾后迭代器指向的那个空节点,而普通节点类型为_List_node<_Tp>,其继承自_List_node_base<_Tp>,里面多一个数据域,其实现如下图所示:
其源码如下所示:
template<typename _Tp,
typename _Alloc = std::allocator<_Tp>>
class list:protected _List_base<_Tp, _Alloc>
{
public:typedef _List_iterator<_Tp> iterator;
......
};
template<typename _Tp>
struct _List_iterator
{
typedef _Tp* pointer;
typedef _Tp& reference;
......
};
struct _List_node_base
{
_List_node_base* _M_next;
_List_node_base* _M_prev;
};
template<typename _Tp>
struct _List_node
: public _List_node_base
{
_Tp _M_data;
};
可以看出节点的指针类型变为了精确类型,并且iterator的模板参数由三个变成了一个,更加容易理解。