首页 > 代码库 > stl源码分析之list
stl源码分析之list
本文主要分析gcc4.8版本的stl list的源码实现,与vector的线性空间结构不同,list的节点是任意分散的,节点之间通过指针连接,好处是在任何位置插入删除元素都只需要常数时间,缺点是不能随机访问,查询复杂度是O(n),n为list中的元素个数。所以list非常适合应用与数据插入删除频繁的场景。
一、 list节点
list节点定义如下,
struct _List_node_base{ _List_node_base* _M_next; _List_node_base* _M_prev;}template<typename _Tp>struct _List_node : public __detail::_List_node_base{ _Tp _M_data;}
很明显list是一个双向链表,_M_next和_M_prev分别指向下一个和上一个节点,_M_data是节点存储的数据。
二、 list的迭代器
由于list不是线性空间结构,通用迭代器无法正常移动,所以list需要定义专门的迭代器。
template<typename _Tp>struct _List_iterator{ typedef _List_iterator<_Tp> _Self; typedef _List_node<_Tp> _Node; typedef ptrdiff_t difference_type; typedef std::bidirectional_iterator_tag iterator_category; typedef _Tp value_type; typedef _Tp* pointer; typedef _Tp& reference; _List_iterator() : _M_node() { } explicit _List_iterator(__detail::_List_node_base* __x) : _M_node(__x) { } // Must downcast from _List_node_base to _List_node to get to _M_data. reference operator*() const { return static_cast<_Node*>(_M_node)->_M_data; } pointer operator->() const { return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); } _Self& operator++() { _M_node = _M_node->_M_next; return *this; } _Self operator++(int) { _Self __tmp = *this; _M_node = _M_node->_M_next; return __tmp; } _Self& operator--() { _M_node = _M_node->_M_prev; return *this; } _Self operator--(int) { _Self __tmp = *this; _M_node = _M_node->_M_prev; return __tmp; } // 指向list节点指针 __detail::_List_node_base* _M_node;};
list迭代器指向list的node,所以解引用时必须返回 static_cast<_Node*>(_M_node)->_M_data。list迭代器不是随机访问迭代器,必须通过节点的next和prev指针一步步移动,元素访问复杂度是线性的。另外还定义了只读迭代器_List_const_iterator。
三、 list的定义
和vector一样,list继承于_List_base,内存分配释放工作由_List_base负责,
template<typename _Tp, typename _Alloc>class _List_base{ protected://使用traits方法,得到_List_node<_Tp>的内存分配器 typedef typename _Alloc::template rebind<_List_node<_Tp> >::other _Node_alloc_type; typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type; struct _List_impl : public _Node_alloc_type { //数据成员就只有一个头节点 __detail::_List_node_base _M_node; _List_impl() : _Node_alloc_type(), _M_node() { } _List_impl(const _Node_alloc_type& __a) : _Node_alloc_type(__a), _M_node() { } }; _List_impl _M_impl;//分配节点的接口 _List_node<_Tp>* _M_get_node() { return _M_impl._Node_alloc_type::allocate(1); } _List_base() : _M_impl() { _M_init(); }//list初始为空,头节点的next和prev都指向自身 void _M_init() { this->_M_impl._M_node._M_next = &this->_M_impl._M_node; this->_M_impl._M_node._M_prev = &this->_M_impl._M_node; }//从第一个数据节点开始依次删除并释放内存。 template<typename _Tp, typename _Alloc> void _List_base<_Tp, _Alloc>:: _M_clear() { typedef _List_node<_Tp> _Node; _Node* __cur = static_cast<_Node*>(_M_impl._M_node._M_next); while (__cur != &_M_impl._M_node) { _Node* __tmp = __cur; __cur = static_cast<_Node*>(__cur->_M_next); _M_get_Node_allocator().destroy(__tmp); _M_put_node(__tmp); }}
list继承了_List_base的头节点,
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >class list : protected _List_base<_Tp, _Alloc>{ // concept requirements typedef typename _Alloc::value_type _Alloc_value_type; __glibcxx_class_requires(_Tp, _SGIAssignableConcept) __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept) typedef _List_base<_Tp, _Alloc> _Base; typedef typename _Base::_Tp_alloc_type _Tp_alloc_type; typedef typename _Base::_Node_alloc_type _Node_alloc_type; public: typedef _Tp value_type; typedef typename _Tp_alloc_type::pointer pointer; typedef typename _Tp_alloc_type::const_pointer const_pointer; typedef typename _Tp_alloc_type::reference reference; typedef typename _Tp_alloc_type::const_reference const_reference; typedef _List_iterator<_Tp> iterator; typedef _List_const_iterator<_Tp> const_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Alloc allocator_type;......
四、 list构造方式
list提供了多种构造函数,
//默认构造函数 list() : _Base() { }//初始化为n个默认值 explicit list(size_type __n) : _Base() { _M_default_initialize(__n); }//初始化为n个__value值list(size_type __n, const value_type& __value, const allocator_type& __a = allocator_type()) : _Base(_Node_alloc_type(__a)) { _M_fill_initialize(__n, __value); }//拷贝构造函数 list(const list& __x) : _Base(__x._M_get_Node_allocator()) { _M_initialize_dispatch(__x.begin(), __x.end(), __false_type()); }//移动构造函数 list(list&& __x) noexcept : _Base(std::move(__x)) { }
五、 list元素操作
篇幅有限,只讨论部分函数。
iterator begin() _GLIBCXX_NOEXCEPT{ return iterator(this->_M_impl._M_node._M_next); } iterator end() _GLIBCXX_NOEXCEPT{ return iterator(&this->_M_impl._M_node); }end指向头节点,begin指向第一个数据节点,begin和end仍然组成一个前闭后开区间。Bool empty() const _GLIBCXX_NOEXCEPT{ return this->_M_impl._M_node._M_next == &this->_M_impl._M_node; }通过查看头节点是否指向自身来判断list是否为空。void push_front(const value_type& __x){ this->_M_insert(begin(), __x); }void push_back(const value_type& __x){ this->_M_insert(end(), __x); }template<typename... _Args> void _M_insert(iterator __position, _Args&&... __args){ _Node* __tmp = _M_create_node(std::forward<_Args>(__args)...); __tmp->_M_hook(__position._M_node);}template<typename _Tp, typename _Alloc> typename list<_Tp, _Alloc>::iterator list<_Tp, _Alloc>::insert(iterator __position, const value_type& __x){ _Node* __tmp = _M_create_node(__x); __tmp->_M_hook(__position._M_node); return iterator(__tmp);}
push_front,push_back和insert的时间复杂度都是O(1).
template<typename _Tp, typename _Alloc>void list<_Tp, _Alloc>::merge(list&& __x){ if (this != &__x) { _M_check_equal_allocators(__x); iterator __first1 = begin(); iterator __last1 = end(); iterator __first2 = __x.begin(); iterator __last2 = __x.end(); while (__first1 != __last1 && __first2 != __last2) if (*__first2 < *__first1) { iterator __next = __first2; _M_transfer(__first1, __first2, ++__next); __first2 = __next; } else ++__first1; if (__first2 != __last2) _M_transfer(__last1, __first2, __last2); }}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。