zoukankan      html  css  js  c++  java
  • 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); }
  • 相关阅读:
    性能测试学习第五天-----Jmeter测试脚本&基础元件使用
    【win10主机】连接virtualbox上【32位winXP系统虚拟机】上启动的mysql
    【win10主机】访问virtualbox上【32位winXP系统虚拟机】上启动的项目
    性能测试学习第四天-----loadrunner:jdbc批量制造测试数据 & controller应用
    appium输入法踩坑解决方案-----中文乱码及输入法搜索无法点击
    性能测试学习第三天-----loadrunner接口测试&中文乱码处理
    Ext JS学习第四天 我们所熟悉的javascript(三)
    Ext JS学习第五天 我们所熟悉的javascript(四)
    ExtJS学习第一天 MessageBox
    C#使用Zxing2.0生成二维码 带简单中心LOGO
  • 原文地址:https://www.cnblogs.com/tsecer/p/10487777.html
Copyright © 2011-2022 走看看