【问题标题】:Check whether iterator belongs to a list检查迭代器是否属于列表
【发布时间】:2011-06-10 06:26:16
【问题描述】:

有什么方法可以检查给定的迭代器是否属于 C++ 中的给定列表?

【问题讨论】:

    标签: c++ stl


    【解决方案1】:

    明显但无效的方法

    您不能简单地遍历列表,将每个迭代器值与您的“候选人”进行比较。

    C++03 标准对应用于来自不同容器的迭代器的 == 的有效性含糊不清(Mankarse 对 Nawaz 的答案链接 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2948.html#446 的评论),一些编译器(例如 VC++2005 调试模式)会发出警告,如果你这样做了,但尽管它实际上可能会根据你的编译器/库而可靠地工作 - 如果你不关心可移植性,请查看它的文档。

    C++11 标准非常明确,不能将迭代器与不同的容器进行比较

    § 24.2.5 前向迭代器的 == 域是相同底层序列上的迭代器的域。

    所以,依赖operator==的这个问题的答案现在是有问题的,将来也是无效的。

    一种经常有效的方法

    可以做的是沿着列表进行迭代,将元素的地址(即&*i)与其他迭代指向的对象的地址进行比较。

    • Mankarse 的评论警告说,这可能不适用于提供自己的 operator& 的对象。您可以使用 std::addressof 或 C++03 boost's version

    • 解决此问题
    • Martin 的评论提到您必须假设您正在测试列表成员资格的候选迭代器是安全可取消引用的 - 即不等于它来自的容器上的 end() 迭代器。正如史蒂夫指出的那样——这是一个相当合理的前提,不应该让任何人感到惊讶。

    (这对于所有标准容器都很好,因为存储的元素永远不会有相同的地址,但更一般地说,用户定义的容器可以允许不相等的迭代器处理相同的值对象(例如,支持循环或“flyweight 模式”样式优化),在这种情况下,这种方法会失败。不过,如果您编写这样的容器,您可能可以设计用于安全迭代器比较。)

    实施:

    template <class IteratorA, class IteratorB, class IteratorC>
    inline bool range_contains(IteratorA from, const IteratorB& end,
                               const IteratorC& candidate)
    {
        while (from != end)
            if (&*from++ == &*candidate)
                return true;
        return false;
    }
    

    注意事项:

    • 这采用了标准库方法,接受一系列迭代器位置进行搜索。
    • 每个迭代器的类型都允许变化,因为存在可移植性问题,例如begin() 返回 iteratorend() 返回 const_iterator 的容器。
    • from 以外的迭代器由const 引用,因为迭代器有时可能是不平凡的对象(即太大而无法放入寄存器,复制起来相对昂贵)。值需要from,因为它将在整个范围内递增。

    【讨论】:

    • @Tony:感谢您对我的回答的评论,这是严重错误的。我只好删除它。经验教训:多任务处理很糟糕,尤其是同时兼顾 SO 和工作!
    • 请注意,这仍然只适用于 ForwardIterators(及其改进),因此在一般情况下需要小心。
    • @Als:我很惊讶,因为我看过你的许多其他答案,并且知道它们通常是多么完美。我经常以同样的方式卡住......不用担心。
    • ... 比较元素的地址 ... -- 当然如果传递的迭代器恰好指向end()(或@987654339 @ 的空列表),再次取消引用它是 UB。真是一团糟! :-)
    • @Tony:我认为这是一个合理的先决条件。唯一可以有效使用end 迭代器(属于 InputIterator 类别)的方法是将其与同一容器中使用==!= 的另一个迭代器进行比较。因此,除非调用者还告诉您迭代器来自哪个容器,否则您必须对迭代器提出一些要求以避免这种情况。
    猜你喜欢
    • 1970-01-01
    • 2011-01-04
    • 2020-03-01
    • 1970-01-01
    • 2023-04-10
    • 2021-01-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    相关资源
    最近更新 更多