顺序容器list
list为环形双向串行链表:
list的节点
以下源码的对应版本为gcc 4.9:
/// Common part of a node in the %list.
struct _List_node_base
{
_List_node_base* _M_next;
_List_node_base* _M_prev;
static void
swap(_List_node_base& __x, _List_node_base& __y) _GLIBCXX_USE_NOEXCEPT;
void
_M_transfer(_List_node_base* const __first,
_List_node_base* const __last) _GLIBCXX_USE_NOEXCEPT;
void
_M_reverse() _GLIBCXX_USE_NOEXCEPT;
void
_M_hook(_List_node_base* const __position) _GLIBCXX_USE_NOEXCEPT;
void
_M_unhook() _GLIBCXX_USE_NOEXCEPT;
};
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace detail
_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
/// An actual node in the %list.
template<typename _Tp>
struct _List_node : public __detail::_List_node_base
{
///< User's data.
_Tp _M_data;
#if __cplusplus >= 201103L
template<typename... _Args>
_List_node(_Args&&... __args)
: __detail::_List_node_base(), _M_data(std::forward<_Args>(__args)...)
{ }
#endif
};
从上述源码可以看出:
- _List_node继承自 _List_node_base,所以可以得到_list_node包含以下三个成员:
_List_node_base* _M_next;
_List_node_base* _M_prev;//< User's data.
_Tp _M_data;
list的迭代器
_List_iterator 的实现如下:
/**
* @brief A list::iterator.
*
* All the functions are op overloads.
*/
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() _GLIBCXX_NOEXCEPT
: _M_node() { }
explicit
_List_iterator(__detail::_List_node_base* __x) _GLIBCXX_NOEXCEPT
: _M_node(__x) { }
_Self
_M_const_cast() const _GLIBCXX_NOEXCEPT
{ return *this; }
// Must downcast from _List_node_base to _List_node to get to _M_data.
reference
operator*() const _GLIBCXX_NOEXCEPT
{ return static_cast<_Node*>(_M_node)->_M_data; }
pointer
operator->() const _GLIBCXX_NOEXCEPT
{ return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); }
_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;
}
bool
operator==(const _Self& __x) const _GLIBCXX_NOEXCEPT
{ return _M_node == __x._M_node; }
bool
operator!=(const _Self& __x) const _GLIBCXX_NOEXCEPT
{ return _M_node != __x._M_node; }
// The only member points to the %list element.
__detail::_List_node_base* _M_node;
};
list的迭代器包含一个成员指针_M_node,指向list链表的节点,如下所示(_M_node对应下图的node):
_List_iterator的几个主要实现:
1. 前++ 与 后 ++的实现
_Self&
operator++() _GLIBCXX_NOEXCEPT
{//对迭代器累加1,就是前进一个节点
//前++ 返回的是加1之后的节点,即下一个节点
_M_node = _M_node->_M_next;
return *this;
}_Self
operator++(int) _GLIBCXX_NOEXCEPT
{//后++ 返回的是当前节点,然后在前进一个节点
_Self __tmp = *this;
_M_node = _M_node->_M_next;
return __tmp;
}
2. 前-- 和 后-- 的实现:
_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;
}
3. -> 和 。操作符的实现:
reference
operator*() const _GLIBCXX_NOEXCEPT
{ return static_cast<_Node*>(_M_node)->_M_data; }pointer
operator->() const _GLIBCXX_NOEXCEPT
{ return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); }
list的类结构
gcc4.9.0 的list的层级结构如下所示:
以下为_List_base的实现,其中类中包含了_List_impl的结构体,在结构体中含有_List_node_base _M_node 成员,就是上文中提到的list的节点。
/// See bits/stl_deque.h's _Deque_base for an explanation.
template<typename _Tp, typename _Alloc>
class _List_base
{
protected:
// NOTA BENE
// The stored instance is not actually of "allocator_type"'s
// type. Instead we rebind the type to
// Allocator<List_node<Tp>>, which according to [20.1.5]/4
// should probably be the same. List_node<Tp> is not the same
// size as Tp (it's two pointers larger), and specializations on
// Tp may go unused because List_node<Tp> is being bound
// instead.
//
// We put this to the test in the constructors and in
// get_allocator, where we use conversions between
// allocator_type and _Node_alloc_type. The conversion is
// required by table 32 in [20.1.5].
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) _GLIBCXX_NOEXCEPT
: _Node_alloc_type(__a), _M_node()
{ }
#if __cplusplus >= 201103L
_List_impl(_Node_alloc_type&& __a) _GLIBCXX_NOEXCEPT
: _Node_alloc_type(std::move(__a)), _M_node()
{ }
#endif
};
_List_impl _M_impl;
_List_node<_Tp>*
_M_get_node()
{ return _M_impl._Node_alloc_type::allocate(1); }
void
_M_put_node(_List_node<_Tp>* __p) _GLIBCXX_NOEXCEPT
{ _M_impl._Node_alloc_type::deallocate(__p, 1); }
public:
typedef _Alloc allocator_type;
_Node_alloc_type&
_M_get_Node_allocator() _GLIBCXX_NOEXCEPT
{ return *static_cast<_Node_alloc_type*>(&_M_impl); }
const _Node_alloc_type&
_M_get_Node_allocator() const _GLIBCXX_NOEXCEPT
{ return *static_cast<const _Node_alloc_type*>(&_M_impl); }
_Tp_alloc_type
_M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
{ return _Tp_alloc_type(_M_get_Node_allocator()); }
allocator_type
get_allocator() const _GLIBCXX_NOEXCEPT
{ return allocator_type(_M_get_Node_allocator()); }
_List_base()
: _M_impl()
{ _M_init(); }
_List_base(const _Node_alloc_type& __a) _GLIBCXX_NOEXCEPT
: _M_impl(__a)
{ _M_init(); }
#if __cplusplus >= 201103L
_List_base(_List_base&& __x) noexcept
: _M_impl(std::move(__x._M_get_Node_allocator()))
{
_M_init();
__detail::_List_node_base::swap(_M_impl._M_node, __x._M_impl._M_node);
}
#endif
// This is what actually destroys the list.
~_List_base() _GLIBCXX_NOEXCEPT
{ _M_clear(); }
void
_M_clear() _GLIBCXX_NOEXCEPT;
void
_M_init() _GLIBCXX_NOEXCEPT
{
this->_M_impl._M_node._M_next = &this->_M_impl._M_node;
this->_M_impl._M_node._M_prev = &this->_M_impl._M_node;
}
};
list的数据结构
list 不仅是一个双向串行,而且还是一个环状双向串行,所以只需一个节点指针,便能表示整个环状双向串行链表,如下图所示:
如果让_List_impl结构体中的_List_node_base _M_node 指向上图中的空白节点,_M_node 就能够符合STL的前闭后开区间的要求,并且只需一个标记就可以表示上述的整个链表,下面体会以下函数的实现:
iterator
begin() _GLIBCXX_NOEXCEPT
{ //_M_node指向空白节点,通过空白节点的_M_next可以获得list的第一个节点
return iterator(this->_M_impl._M_node._M_next);
}iterator
end() _GLIBCXX_NOEXCEPT
{
//STL的规范要求容器的区间为前闭后开,end 表示的是容器最后一个元素的下一个位置,
//所以这里end 返回的是当前的空白节点
return iterator(&this->_M_impl._M_node);
}reference
back() _GLIBCXX_NOEXCEPT
{ //取尾节点的内容
iterator __tmp = end();
--__tmp;
return *__tmp;
}bool
empty() const _GLIBCXX_NOEXCEPT
{ //空节点的判断
return this->_M_impl._M_node._M_next == &this->_M_impl._M_node;
}
list的构造和内存管理
构造函数
1. 无参构造函数:
/**
* @brief Creates a %list with no elements.
*/
list()
#if __cplusplus >= 201103L
noexcept(is_nothrow_default_constructible<_Node_alloc_type>::value)
#endif
: _Base() { }
2. 带构造器的构造函数:
/**
* @brief Creates a %list with no elements.
* @param __a An allocator object.
*/
explicit
list(const allocator_type& __a) _GLIBCXX_NOEXCEPT
: _Base(_Node_alloc_type(__a)) { }
3. 带n个元素且赋予初值的list
/**
* @brief Creates a %list with copies of an exemplar element.
* @param __n The number of elements to initially create.
* @param __value An element to copy.
* @param __a An allocator object.
*
* This constructor fills the %list with @a __n copies of @a __value.
*/
explicit
list(size_type __n, const value_type& __value = value_type(),
const allocator_type& __a = allocator_type())
: _Base(_Node_alloc_type(__a))
{ _M_fill_initialize(__n, __value); }
4. 从一个范围进行初始化的list构造函数
template<typename _InputIterator>
list(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type())
: _Base(_Node_alloc_type(__a))
{
// Check whether it's an integral type. If so, it's not an iterator.
typedef typename std::__is_integer<_InputIterator>::__type _Integral;
_M_initialize_dispatch(__first, __last, _Integral());
}
_M_fill_initialize的实现
在构造函数:
explicit
list(size_type __n, const value_type& __value = value_type(),
const allocator_type& __a = allocator_type())中使用了_M_fill_initialize,来看下_M_fill_initialize的实现细节:
// Called by list(n,v,a), and the range constructor when it turns out
// to be the same thing.
void
_M_fill_initialize(size_type __n, const value_type& __x)
{
for (; __n; --__n)
push_back(__x);
}
push_back的实现如下:
/**
* @brief Add data to the end of the %list.
* @param __x Data to be added.
*
* This is a typical stack operation. The function creates an
* element at the end of the %list and assigns the given data to
* it. Due to the nature of a %list this operation can be done
* in constant time, and does not invalidate iterators and
* references.
*/
void
push_back(const value_type& __x)
{ this->_M_insert(end(), __x); }
_M_insert的实现:
void
_M_insert(iterator __position, const value_type& __x)
{
_Node* __tmp = _M_create_node(__x);
__tmp->_M_hook(__position._M_node);
}
_M_hook的实现(gcc-4.9.0\gcc-4.9.0\libstdc++-v3\src\c++98\list.cc):
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;
}
通过以上的源码分析,可以知道_M_fill_initialize就是在尾部插入n个指定值的节点,每个节点通过_M_create_node来创建。
节点的创建与删除
节点的创建:
_Node*
_M_create_node(const value_type& __x)
{
_Node* __p = this->_M_get_node();
__try
{
_M_get_Tp_allocator().construct(std::__addressof(__p->_M_data), __x);
}
__catch(...)
{
_M_put_node(__p);
__throw_exception_again;
}
return __p;
}
_M_get_node,_M_put_node的实现主要就是进行内存的分配与释放:
_List_node<_Tp>*
_M_get_node()
{
return _M_impl._Node_alloc_type::allocate(1);
}void
_M_put_node(_List_node<_Tp>* __p) _GLIBCXX_NOEXCEPT
{
_M_impl._Node_alloc_type::deallocate(__p, 1);
}
list的元素操作
1. 移除节点
void
pop_front() _GLIBCXX_NOEXCEPT
{//删除第一个元素
this->_M_erase(begin());
}void
pop_back() _GLIBCXX_NOEXCEPT
{// 删除尾部节点
this->_M_erase(iterator(this->_M_impl._M_node._M_prev));
}
_M_erase的实现:
// Erases element at position given.
void
_M_erase(iterator __position) _GLIBCXX_NOEXCEPT
{
__position._M_node->_M_unhook();
_Node* __n = static_cast<_Node*>(__position._M_node);
#if __cplusplus >= 201103L
_M_get_Node_allocator().destroy(__n);//调用配置器释放内存
#else
_M_get_Tp_allocator().destroy(std::__addressof(__n->_M_data));
#endif
_M_put_node(__n);//删除节点
}
_M_unhook的实现:
_M_unhook的实现看着就是个const的转换,不知道有没有其他的作用?
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;
}
2. 在指定迭代器之前插入n个指定节点值的节点。
void insert(iterator __position, size_type __n, const value_type &__x) {
list __tmp(__n, __x, get_allocator());//先构造一个含有n个节点的list,并初始化节点的值围为 __x
splice(__position, __tmp);
}
splice的实现:
splice(iterator __position, list& __x)
{
if (!__x.empty())
{
_M_check_equal_allocators(__x);this->_M_transfer(__position._M_const_cast(),
__x.begin(), __x.end());
}}
_M_transfer的实现:
// Moves the elements from [first,last) before position.
void
_M_transfer(iterator __position, iterator __first, iterator __last)
{ __position._M_node->_M_transfer(__first._M_node, __last._M_node); }
_List_node_base::_M_transfer的实现(这里注意first与last表示的区间是 前闭后开):
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;
}
}