C++进阶——STL源码之顺序容器list

14 篇文章 4 订阅

顺序容器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;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值