【问题标题】:Why does end() in stl_tree.h return a reference to the iterator object but begin() returns object?为什么 stl_tree.h 中的 end() 返回对迭代器对象的引用,而 begin() 返回对象?
【发布时间】:2014-07-30 09:11:31
【问题描述】:

在 GCC stl_tree.h 中:

https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.1/stl__tree_8h-source.html

begin()end() 返回迭代器对象。但是end() 返回对象的地址,而begin() 返回对象本身。

  1. 为什么会有这种差异?
  2. begin() 返回一个对象是否意味着需要访问另一块内存,该内存包含按值传递的迭代器对象?

.......

00589       iterator begin()
00590       { 
00591     return iterator(static_cast<_Link_type>
00592             (this->_M_impl._M_header._M_left));
00593       }
00594 
00595       const_iterator
00596       begin() const
00597       { 
00598     return const_iterator(static_cast<_Const_Link_type>
00599                   (this->_M_impl._M_header._M_left));
00600       }
00601 
00602       iterator
00603       end()
00604       { return iterator(static_cast<_Link_type>(&this->_M_impl._M_header)); }
00605 
00606       const_iterator
00607       end() const
00608       { 
00609     return const_iterator(static_cast<_Const_Link_type>
00610                   (&this->_M_impl._M_header));
            }

地点:

typedef _Rb_tree_iterator<_Tp> iterator;
typedef _Rb_tree_const_iterator<value_type> const_iterator;

和:

template<typename _Tp>
00221     struct _Rb_tree_const_iterator
00222     {
00223       typedef _Tp        value_type;
00224       typedef const _Tp& reference;
00225       typedef const _Tp* pointer;
00226 
00227       typedef _Rb_tree_iterator<_Tp> iterator;
00228 
00229       typedef bidirectional_iterator_tag iterator_category;
00230       typedef ptrdiff_t                  difference_type;
00231 
00232       typedef _Rb_tree_const_iterator<_Tp>        _Self;
00233       typedef _Rb_tree_node_base::_Const_Base_ptr _Base_ptr;
00234       typedef const _Rb_tree_node<_Tp>*           _Link_type;
00235 
00236       _Rb_tree_const_iterator()
00237       : _M_node() { }
00238 
00239       explicit
00240       _Rb_tree_const_iterator(_Link_type __x)
00241       : _M_node(__x) { }
00242 
00243       _Rb_tree_const_iterator(const iterator& __it)
00244       : _M_node(__it._M_node) { }
00245 
00246       reference
00247       operator*() const
00248       { return static_cast<_Link_type>(_M_node)->_M_value_field; }
00249 
00250       pointer
00251       operator->() const
00252       { return &static_cast<_Link_type>(_M_node)->_M_value_field; }
00253 
00254       _Self&
00255       operator++()
00256       {
00257     _M_node = _Rb_tree_increment(_M_node);
00258     return *this;
00259       }
00260 
00261       _Self
00262       operator++(int)
00263       {
00264     _Self __tmp = *this;
00265     _M_node = _Rb_tree_increment(_M_node);
00266     return __tmp;
00267       }
00268 
00269       _Self&
00270       operator--()
00271       {
00272     _M_node = _Rb_tree_decrement(_M_node);
00273     return *this;
00274       }
00275 
00276       _Self
00277       operator--(int)
00278       {
00279     _Self __tmp = *this;
00280     _M_node = _Rb_tree_decrement(_M_node);
00281     return __tmp;
00282       }
00283 
00284       bool
00285       operator==(const _Self& __x) const
00286       { return _M_node == __x._M_node; }
00287 
00288       bool
00289       operator!=(const _Self& __x) const
00290       { return _M_node != __x._M_node; }
00291 
00292       _Base_ptr _M_node;
00293     };

和:

template<typename _Tp>
00151     struct _Rb_tree_iterator
00152     {
00153       typedef _Tp  value_type;
00154       typedef _Tp& reference;
00155       typedef _Tp* pointer;
00156 
00157       typedef bidirectional_iterator_tag iterator_category;
00158       typedef ptrdiff_t                  difference_type;
00159 
00160       typedef _Rb_tree_iterator<_Tp>        _Self;
00161       typedef _Rb_tree_node_base::_Base_ptr _Base_ptr;
00162       typedef _Rb_tree_node<_Tp>*           _Link_type;
00163 
00164       _Rb_tree_iterator()
00165       : _M_node() { }
00166 
00167       explicit
00168       _Rb_tree_iterator(_Link_type __x)
00169       : _M_node(__x) { }
00170 
00171       reference
00172       operator*() const
00173       { return static_cast<_Link_type>(_M_node)->_M_value_field; }
00174 
00175       pointer
00176       operator->() const
00177       { return &static_cast<_Link_type>(_M_node)->_M_value_field; }
00178 
00179       _Self&
00180       operator++()
00181       {
00182     _M_node = _Rb_tree_increment(_M_node);
00183     return *this;
00184       }
00185 
00186       _Self
00187       operator++(int)
00188       {
00189     _Self __tmp = *this;
00190     _M_node = _Rb_tree_increment(_M_node);
00191     return __tmp;
00192       }
00193 
00194       _Self&
00195       operator--()
00196       {
00197     _M_node = _Rb_tree_decrement(_M_node);
00198     return *this;
00199       }
00200 
00201       _Self
00202       operator--(int)
00203       {
00204     _Self __tmp = *this;
00205     _M_node = _Rb_tree_decrement(_M_node);
00206     return __tmp;
00207       }
00208 
00209       bool
00210       operator==(const _Self& __x) const
00211       { return _M_node == __x._M_node; }
00212 
00213       bool
00214       operator!=(const _Self& __x) const
00215       { return _M_node != __x._M_node; }
00216 
00217       _Base_ptr _M_node;
00218   };

【问题讨论】:

    标签: c++ gcc stl set red-black-tree


    【解决方案1】:

    .end() 处没有对象;它不存在。这是一个“过去的”迭代器。因此,.end() 必须使用可识别的“哨兵值”来实现,这就是您在此处看到的。

    (另外,请注意它是&amp;this-&gt;_M_impl._M_header,而不是&amp;this-&gt;_M_impl._M_header._M_left!)

    一个非常松散的类比是在 C 字符串末尾找到的 NULL 字符,当然在这种情况下你会找到 NULL 值。

    可以说,可以实现一棵树,使其始终具有至少一个从前端界面隐藏的节点,并且可以将该节点用作end();那么这些函数看起来会更符合您的预期,但效率不会很高,您也不会获得任何收益。

    【讨论】:

    • 谢谢!两者之间的内存访问次数如何比较?我可以看到 begin() 访问另一个级别的间接,那么 begin() 的内存访问是否比 end() 多一个?
    • 此外,如果树为空,则 .begin() 处也不一定有任何对象。在这种情况下,.begin() == .end()。
    • @DanKorn:这实际上提出了一个有趣的观点,因为在代码的这个低级别 .begin() == .end() 显然是错误的 (FSVO ==),即使在那种情况下也是如此。
    • @Lightness, .begin() == .end() 在树为空时绝对正确。否则,标准迭代 for (iterator it = begin(); it != end(); it++) 将无法正确处理这种情况。
    • @DanKorn 你没有正确阅读我的评论。 FSVO 的意思是“为了某种价值”。在这种情况下,表达式.begin() == .end() 当然必须是true,但我已经指出,如果您查看代码,即使在这种情况下,那些迭代器的 representation 也完全不等价.这很有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-28
    相关资源
    最近更新 更多