STL源码剖析——序列容器之list

本文详细剖析了STL中的list容器,它是一个基于双向链表的数据结构,内存效率高,插入和删除操作为O(1)。list容器的迭代器是双向迭代器,插入和拼接操作不会使迭代器失效。文章涵盖了list的节点结构、迭代器实现、构造函数、成员函数以及操作符重载,通过源码分析帮助理解其工作原理。
摘要由CSDN通过智能技术生成

前言

    在SGI STL中,list容器是一个循环的双向链表,它的内存空间效率较前文介绍的vector容器高。因为vector容器的内存空间是连续存储的,且在分配内存空间时,会分配额外的可用空间;而list容器的内存空间不一定是连续存储,内存之间是采用迭代器或节点指针进行连接,并且在插入或删除数据节点时,就配置或释放一个数据节点,并不会分配额外的内存空间,这两个操作过程都是常数时间。

    与vector容器不同的是list容器在进行插入操作或拼接操作时,迭代器并不会失效;且不能以普通指针作为迭代器,因为普通指针的+或-操作只能指向连续空间的后移地址或前移个地址,不能保证指向list的下一个节点,迭代器必须是双向迭代器,因为list容器具备有前移和后移的能力。

    注:本文所列的源码出自SGI STL中的文件<stl_list.h>,对于list容器类的详细信息也可以查看list容器库》MSDNlist类》

list容器

list节点和list数据结构

    在list容器中,list本身和list节点是分开设计的,list节点结构是存储数据和指向相邻节点的指针;如下源码所示:

//以下是list链表节点的数据结构
struct _List_node_base {
  _List_node_base* _M_next;//指向直接后继节点
  _List_node_base* _M_prev;//指向直接前驱节点
};

template <class _Tp>
struct _List_node : public _List_node_base {
  _Tp _M_data;//节点存储的数据
};
       list 本身的数据结构是只有一个指向链表节点的指针,因为 list 容器是循环双向链表,则足够遍历整个链表;如下源码所示:

//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> { 
	 ...
public:
	typedef _List_node<_Tp> _Node;
protected:
	//定义指向链表节点指针
	_List_node<_Tp>* _M_node;
	...
};
    下面给出 list节点和list本身的数据结构图:


list容器的迭代器

       list容器的内存空间存储不一定是连续的,则不能用普通指针做为迭代器;list容器的迭代器是双向迭代器,这也是导致list容器的排序成员函数sort()不能使用STL算法中的排序函数,因为STL中的排序算法接受的迭代器是随机访问迭代器;list容器在进行插入和拼接操作时迭代器不会失效;以下是源码对迭代器的定义:

//以下是链表List_iterator_base的迭代器
struct _List_iterator_base {
	//数据类型
  typedef size_t                     size_type;
  typedef ptrdiff_t                  difference_type;
  //list迭代器的类型是双向迭代器bidirectional_iterator
  typedef bidirectional_iterator_tag iterator_category;

  //定义指向链表节点的指针
  _List_node_base* _M_node;

  //构造函数
  _List_iterator_base(_List_node_base* __x) : _M_node(__x) {}
  _List_iterator_base() {}

  //更新节点指针,指向直接前驱或直接后继节点
  void _M_incr() { _M_node = _M_node->_M_next; }
  void _M_decr() { _M_node = _M_node->_M_prev; }

  //操作符重载
  bool operator==(const _List_iterator_base& __x) const {
    return _M_node == __x._M_node;
  }
  bool operator!=(const _List_iterator_base& __x) const {
    return _M_node != __x._M_node;
  }
};  

//以下是链表List_iterator的迭代器
template<class _Tp, class _Ref, class _Ptr>
struct _List_iterator : public _List_iterator_base {
  typedef _List_iterator<_Tp,_Tp&,_Tp*>             iterator;
  typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
  typedef _List_iterator<_Tp,_Ref,_Ptr>             _Self;

  typedef _Tp value_type;
  typedef _Ptr pointer;
  typedef _Ref reference;
  typedef _List_node<_Tp> _Node;

  //构造函数
  _List_iterator(_Node* __x) : _List_iterator_base(__x) {}
  _List_iterator() {}
  _List_iterator(const iterator& __x) : _List_iterator_base(__x._M_node) {}

  //以下都是基本操作符的重载,取出节点数据
  reference operator*() const { return ((_Node*) _M_node)->_M_data; }

#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

  _Self& operator++() { 
    this->_M_incr();
    return *this;
  }
  _Self operator++(int) { 
    _Self __tmp = *this;
    this->_M_incr();
    return __tmp;
  }
  _Self& operator--() { 
    this->_M_decr();
    return *this;
  }
  _Self operator--(int) { 
    _Self __tmp = *this;
    this->_M_decr();
    return __tmp;
  }
};

#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION

//返回迭代器的类型
inline bidirectional_iterator_tag
iterator_category(const _List_iterator_base&)
{
  return bidirectional_iterator_tag();
}

template <class _Tp, class _Ref, class _Ptr>
inline _Tp*
value_type(const _List_iterator<_Tp, _Ref, _Ptr>&)
{
  return 0;
}

inline ptrdiff_t*
distance_type(const _List_iterator_base&)
{
  return 0;
}

#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

list容器的构造函数和析构函数

    这里把list容器的构造函数列出来讲解,使我们对list容器的构造函数进行全面的了解,以便我们对其使用。在以下源码的前面我会总结出list容器的构造函数及其使用方法。

//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> { 
	 ...
public:
 //**********************************************************************
  /***********************以下是构造函数**********************************
  //*******************默认构造函数***************************************
	explicit list( const Allocator& alloc = Allocator() );
  //**********************具有初值和大小的构造函数************************
	explicit list( size_type count,
               const T& value = T(),
               const Allocator& alloc = Allocator());
         list( size_type count,
               const T& value,
               const Allocator& alloc = Allocator());
  //**************只有大小的构造函数**************************************
	explicit list( size_type count );
  //************某个范围的值为初始值的构造函数****************************
	template< class InputIt >
	list( InputIt first, InputIt last,
      const Allocator& alloc = Allocator() );
 //************拷贝构造函数***********************************************
	list( const list& other );
  */
  //**********************************************************************
  //构造函数
  //链表的默认构造函数
  explicit list(const allocator_type& __a = allocator_type()) : _Base(__a) {}
  list(size_type __n, const _Tp& __value,
       const allocator_type& __a = allocator_type())
    : _Base(__a)
    { insert(begin(), __n, __value); }
  explicit list(size_type __n)
    : _Base(allocator_type())
    { insert(begin(), __n, _Tp()); }

#ifdef __STL_MEMBER_TEMPLATES

  // We don't need any dispatching tricks here, because insert does all of
  // that anyway.  
  template <class _InputIterator>
  list(_InputIterator __first, _InputIterator __last,
       const allocator_type& __a = allocator_type())
    : _Base(__a)
    { insert(begin(), __first, __last); }

#else /* __STL_MEMBER_TEMPLATES */

  list(const _Tp* __first, const _Tp* __last,
       const allocator_type& __a = allocator_type())
    : _Base(__a)
    { this->insert(begin(), __first, __last); }
  list(const_iterator __first, const_iterator __last,
       const allocator_type& __a = allocator_type())
    : _Base(__a)
    { this->insert(begin(), __first, __last); }

#endif /* __STL_MEMBER_TEMPLATES */
  list(const list<_Tp, _Alloc>& __x) : _Base(__x.get_allocator())
    { insert(begin(), __x.begin(), __x.end()); }//拷贝构造函数

  ~list() { }//析构函数

  //赋值操作
  list<_Tp, _Alloc>& operator=(const list<_Tp, _Alloc>& __x);
  //构造函数,析构函数,赋值操作 定义到此结束
  //*******************************************************************
	...
};

list容器的成员函数

    list容器的成员函数为我们使用该容器提供了很大的帮助,所以这里对其进行讲解,首先先给出源码的剖析,然后在对其中一些重点的成员函数进行图文讲解;具体源码剖析如下所示:

//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> {
  // requirements:

	...

protected:
	//创建值为x的节点,并返回该节点的地址
  _Node* _M_create_node(const _Tp& __x)
  {
    _Node* __p = _M_get_node();//分配一个节点空间
    __STL_TRY {//把x值赋予指定的地址,即是data值
      _Construct(&__p->_M_data, __x);
    }
    __STL_UNWIND(_M_put_node(__p));
    return __p;//返回节点地址
  }

  //创建默认值的节点
  _Node* _M_create_node()
  {
    _Node* __p = _M_get_node();
    __STL_TRY {
      _Construct(&__p->_M_data);
    }
    __STL_UNWIND(_M_put_node(__p));
    return __p;
  }

public:
	

  //以下是迭代器的定义
  iterator begin()             { return (_Node*)(_M_node->_M_next); }
  const_iterator begin() const { return (_Node*)(_M_node->_M_next); }

  iterator end()             { return _M_node; }
  const_iterator end() const { return _M_node; }

  reverse_iterator rbegin() 
    { return re
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值