【问题标题】:How is STL iterator equality established?STL 迭代器相等性是如何建立的?
【发布时间】:2010-10-25 02:12:05
【问题描述】:

我想知道,如何为 STL 迭代器建立相等 (==)? 它是简单的指针比较(因此基于地址)还是更花哨的东西?

如果我有来自两个不同列表对象的两个迭代器并比较它们,结果是否总是错误的?

如果我将有效值与超出范围的值进行比较会怎样?总是假的吗?

【问题讨论】:

    标签: c++ stl


    【解决方案1】:

    如果需要,迭代器类可以定义重载的 == 运算符。所以结果取决于operator==的实现。

    您实际上不应该比较来自不同容器的迭代器。如果你这样做,我认为一些调试 STL 实现会发出警告,这将帮助你在代码中发现这种错误使用的情况。

    【讨论】:

    • 真的不应该?你绝对不能!
    • 在技术上比较来自不同容器的迭代器的能力使得 MSVC 在使用std::copy时会发出恼人的弃用警告...
    【解决方案2】:

    丹尼尔问: 我想知道,如何为 STL 迭代器建立平等(==)?它是简单的指针比较(因此基于地址)还是更花哨的东西?

    这取决于实施。现在,在 Visual C++ 2008 上,我看到以下代码(用于列表迭代器):

    bool operator==(const _Myt_iter& _Right) const
    {   // test for iterator equality
    
    #if _HAS_ITERATOR_DEBUGGING
        _Compat(_Right);
    #else
        _SCL_SECURE_TRAITS_VALIDATE(this->_Has_container() && this->_Same_container(_Right));
    #endif /* _HAS_ITERATOR_DEBUGGING */
    
        return (_Ptr == _Right._Ptr);
    }
    

    您将在上面看到验证迭代器有效性的代码和_Ptr 是指向列表节点的指针。

    所以我想既有验证,也有简单的原始指针比较。

    丹尼尔问: 如果我有来自两个不同列表对象的两个迭代器并比较它们,结果是否总是错误的?

    到目前为止,该标准似乎在该主题上有些不清楚。显然,他们会明确写出这种操作有未定义的结果:

    引用:http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#446

    使用任何迭代器操作的结果 (24.2.1 [input.iterators], 24.2.2 [output.iterators], 24.2.3 [forward.iterators], 24.2.4 [bidirectional .iterators], 24.2.5 [random.access.iterators]) 使用两个迭代器值作为参数(脚注)从两个不同的范围获得 r1 和 r2 (包括它们的过去值)不是一个公共范围的子范围未定义,除非另有明确说明。

    footnote) 这些操作包括 ==、

    所以我想比较来自不同容器的迭代器是邪恶的...... ^_^

    丹尼尔问: 如果我将一个有效值与一个超出范围的值进行比较怎么办?总是假的吗?

    同上。

    【讨论】:

      【解决方案3】:

      我想知道,如何为 STL 迭代器建立相等 (==)?

      并非所有迭代器都可以进行比较(例如,输出迭代器不需要提供op==)。当范围的概念为正在考虑的迭代器类别明确定义时,您可以使用operator==

      是简单的指针比较(因此基于地址)还是更花哨的东西?

      迭代器总是用指针实现的。编辑:我说 implemented with - 这不是指标准要求,而是指使用 poitners 作为底层构造的做法。不过,实现(如 VS)可能会插入特殊的验证检查。

      如果我有来自两个不同列表对象的两个迭代器并比较它们,结果是否总是错误的?

      您正在调用未定义的行为。

      如果我将有效值与超出范围的值进行比较会怎样?总是假的吗?

      再次,您将调用 UB。唯一有效的比较是在同一范围内的两个迭代器之间或在范围内的一个迭代器和另一个与最后一个元素之后的迭代器之间进行比较。请注意,您只能将迭代器与最后一个元素进行比较,取消引用相同的导致 UB。

      【讨论】:

      • “迭代器总是作为指针实现”。我不认为 insert_iterator 是一个简单的指针。我希望它是一个包含指向容器的指针或引用的对象,以及该容器上的迭代器。
      • 查一下。我见过的实现确实使用了指向容器的指针。
      • 只有 std::vector::iterator 保证可以转换为指针。许多人可能使用指向他们的节点的指针。有些使用两个指针。有些可能使用文件指针。然后你能声称它们是作为指针实现的吗?我不这么认为。我不敢在此基础上进行任何设计。
      • 我说它们是作为指针实现 -- 这与说它们与指针相同。
      • @dirkgently:我认为如果您说“实现 with 指针”(即,迭代器类包含它们最终委托的指针),那会更好一些而不是说“实现 as 指针”(即迭代器类是指针,使用“is-a”的标准 OO 定义)。
      【解决方案4】:

      相等性测试特定于您正在使用的迭代器类型,或者可能根本不存在。如果你真的想知道,你可以随时查看你正在使用的 STL 的实现源代码,在迭代器类中查找 operator==()。

      迭代器并不总是指针,事实上在某些“安全”版本的 STL 中,迭代器从不是指针。向量和字符串的迭代器通常被实现为指针,因为它们可以。用于双端队列、列表、集合和映射的迭代器在任何半有效实现中都不能是指针。

      迭代器是一种智能指针。它们遵循一般原则,即如果它们的外观和行为都像指针,那么就用户而言,它们指针。

      【讨论】:

        猜你喜欢
        • 2012-03-14
        • 1970-01-01
        • 2012-01-21
        • 1970-01-01
        • 1970-01-01
        • 2011-02-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多