![602f102fab26e97dc54d67e9f1b743e2.png](https://img-blog.csdnimg.cn/img_convert/602f102fab26e97dc54d67e9f1b743e2.png)
写在前面
(本文是个人笔记,有胡言乱语和少数错漏部分)
这篇笔记图解了STL中std::list
的实现,并结合代码分析了其迭代器,结点定义,部分成员函数的实现。
最后,仿造std::list
的代码,在Leetcode 146. LRU缓存机制中实现了list的部分功能。
总结list的几个要点:
- list仅持有一个指针p(即 _M_node),指向哨兵节点。p作为end()的返回值。p->next是头节点,也是begin()的返回值,p->prev是back()的返回值。
- 当list为空时,p->prev = p->next = p;
- 哨兵节点的数据域可以充当size使用
好啦,只要记住以上几点,并正确的移动指针,就可以随时随地写出list的代码了。
什么是list
list即环状双向链表,即Circular Double Linked List。
list的继承层次
list定义在stl_list.h 中,它的继承关系如下所示:
list-> _List_base [_List_impl -->_Node_alloc_type]
list继承自_LIst_base,而_List_base内含了一个_List_impl类,而_List_impl继承自_Node_alloc_type。 _Node_alloc_type是allocator<_Tp>经过rebind得到的,详见另一篇文章《STL中的vector》实现。
结点定义
结点也具有继承关系: _List_node --> _List_node_base
它们的定义如下:
//gcc 5.4.0 stl_list.h
77 struct _List_node_base
78 {
79 _List_node_base* _M_next;
80 _List_node_base* _M_prev;
97 };
98
105 template<typename _Tp>
106 struct _List_node : public __detail::_List_node_base
107 {
108 ///< User's data.
109 _Tp _M_data;
117 };
注意,这里_M_data的类型是_Tp而不是_Tp *
。
迭代器定义
- 总的来说,迭代器是一个_List_node_base型的指针。
- 令我感到不解的是,为什么不是_List_node<_Tp>型的指针。现在因为_M_node是_List_node_base型的指针,当我们想要访问_M_node->_M_data的时候,我们需要进行强制类型转换 static_cast<_List_node<_Tp>>(_M_node)->_M_data。
注:强制类型转换的本质在于地址其实是没有类型的。我们赋予了它的类型,当我们将指针p从A类型转换成B类型时,不管p是否是B类型的,我们总能够p->data_member