stl中容器的end指向哪里

一、问题
在很多的C++容器使用,通常的遍历方法都是
for (auto iter = cont.begin(); iter != cont.end(); iter++)
或者使用更高级的C++语法
for (auto &iter : cont)
但是无论如何,在这种场景下,我们总是假设一个容器的end()接口指向的总是一个无效的位置。对于数组来说,这个无效的位置比较简单,那就是这个数组最后一个有效元素的后一个位置;这个位置没有包含数组的有效元素,但是用来定界已经足够了。
那么对于map这类内部是通过树结构来实现的节点,它的end()需要指向哪里呢?如果end()返回的位置指向的是一个NULL,起始也没有什么问题。但是这样以来,就没有办法对这个迭代器执行递减操作(也就是 operator --)操作,从而违背了map的迭代器是双向迭代器的要求。
 
二、vector
这个是容器类中最为简单的一种实现方式了,begin指向连续空间的开始,而end指向连续空间中最后一个有效元素之后的位置。所以这个end()指向的位置不在数组的有效范围之内,但是和最后一个元素紧密相连。当知道最后一个有效元素位置的时候,直接递减一下就可以获得这个位置。
 
三、List
从实现中可以看到,在List容器中保存了一个对使用这个不可见的_List_node_base _M_node;成员,end()始终指向该位置,在刚开始初始化的时候,begin()也指向这里,所以begin()和end()相等
gcc-4.4.7libstdc++-v3includeitsstl_list.h
其中同样是保存了一个用于表示头文件位置的node节点
      struct _List_impl 
      : public _Node_alloc_type
      {
_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;
 
      /**
       *  Returns a read/write iterator that points one past the last
       *  element in the %list.  Iteration is done in ordinary element
       *  order.
       */
      iterator
      end()
      { return iterator(&this->_M_impl._M_node); }
 
四、hashtable
hashtable在标准库中主要用于一些unordered_XX类型的库,例如unordered_map,容器中的这些元素没有严格的大小顺序。
和所有的常规hashtable一样,在存储中使用的是分不同的桶结构来存储所有元素,对应地,容器的end()指向最后一个有效桶结构的后一个元素。
gcc-4.4.7libstdc++-v3include r1_implhashtable
      iterator
      end()
      { return iterator(_M_buckets + _M_bucket_count); }
这里的hashtable有一个有意思的特性,它是一个典型的单项迭代器,这个容器的迭代器只能进行++操作而不能进行--操作。
 
五、基于红黑树的容器
1、红黑树
stl中的要求n*log(n)效率级别容器通常都是基于红黑树实现,典型的容器包含了set和map两种类型。对于红黑树模版来说,它内部存储的是一个个的节点。但是为了提供排序功能,这里有一个限制是要求每个节点能够提供从节点提取键值的接口,也就是红黑树定义中模版参数_KeyOfValue的意义。
gcc-4.4.7libstdc++-v3includeitsstl_tree.h
  template<typename _Key, typename _Val, typename _KeyOfValue,
           typename _Compare, typename _Alloc = allocator<_Val> >
    class _Rb_tree
对于set类容器,这个提取就是容器中类型本身。而对于map类型,红黑树中存储的是一个通过std::pair封装的<key,value>元组,它的_KeyOfValue定义为从元组中提取第一个元素:
gcc-4.4.7libstdc++-v3includeitsstl_map.h
typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
       key_compare, _Pair_alloc_type> _Rep_type;
2、end指向的位置
在树结构初始化时执行_M_initialize函数,该函数将红黑树内部、对用户不直接可见的根节点_M_header的左右指针均指向自己
gcc-4.4.7libstdc++-v3includeitsstl_tree.h
    protected:
      template<typename _Key_compare, 
       bool _Is_pod_comparator = __is_pod(_Key_compare)>
        struct _Rb_tree_impl : public _Node_allocator
        {
……
  _Rb_tree_impl()
  : _Node_allocator(), _M_key_compare(), _M_header(),
    _M_node_count(0)
  { _M_initialize(); }
 
  _Rb_tree_impl(const _Key_compare& __comp, const _Node_allocator& __a)
  : _Node_allocator(__a), _M_key_compare(__comp), _M_header(),
    _M_node_count(0)
  { _M_initialize(); }
 
private:
  void
  _M_initialize()
  {
    this->_M_header._M_color = _S_red;
    this->_M_header._M_parent = 0;
    this->_M_header._M_left = &this->_M_header;
    this->_M_header._M_right = &this->_M_header;
  }
而end()返回的位置也是这个不可见的内部根节点
 
      _Link_type
      _M_end()
      { return static_cast<_Link_type>(&this->_M_impl._M_header); }
 
      _Const_Link_type
      _M_end() const
      { return static_cast<_Const_Link_type>(&this->_M_impl._M_header); }
原文地址:https://www.cnblogs.com/tsecer/p/10487777.html