【问题标题】:Are C++ iterators "safe"?C++ 迭代器“安全”吗?
【发布时间】:2011-06-16 03:48:52
【问题描述】:

我已阅读 C++ 列表迭代器的文档,但无法弄清楚一件事:C++ 迭代器“安全”吗?我的意思是,一旦到达列表中的最后一个现有元素,它会停止递增吗?

[]的

【问题讨论】:

  • @Karmastan - 不幸的是,在 C++ 中,这种实验没有什么价值。
  • @David Heffernan - 这样的迭代器在 C++ 中很常见。理由是性能。
  • 不安全的迭代器应该促使你直接放弃使用它们,而改用算法,让算法担心何时停止递增。
  • @JerryCoffin 这并不总是足够的。例如,如果您有一个迭代器iter 指向std::list<T> l,并且您调用l.erase(iter),那么您必须确保不再使用iter。函数调用后iter无效。

标签: c++ stl iterator


【解决方案1】:

要回答您的问题,“不”他们不会停下来,因为所有者有责任检查边界。

但是,可以将检查放入代理迭代器并强制执行边界检查。这会让你付出代价,因为很可能会付出代价。大多数 std 算法现在对输入和输出迭代器都有第一个/最后一个(请参阅 std::copy( first_in, last_in, first_out, last_out ),并将检查边界以及不以输出结尾的那些并不总是有效的操作(例如,直到流的结束才知道 它发生了)

您可以编写一个包含迭代器副本、第一个位置和最后一个位置的迭代器代理。然后检查它是否会超出 operator++、operator-- 以及访问成员或取消引用时的范围。它与编写骨架容器几乎是相同的工作,并且可以这样使用。一个小例子见Iterator Proxy Example,然后在使用Iterator Proxy Usage Example

【讨论】:

    【解决方案2】:

    没有。像 C++ 中的许多东西一样,默认值是速度。

    理由是您以后可以用速度换取安全,但反之则不行。

    【讨论】:

      【解决方案3】:

      不,从这个意义上说,它们并不“安全”。可以将迭代器递增到末尾。对于标准库中的所有迭代器,这样做将导致未定义的行为。如果您愿意,您可以定义自己的迭代器以安全的方式运行。

      【讨论】:

      • 这过于简单化了。它们是否总是安全的:不。它们是否安全是的(调试版本有时会提供检查的迭代器)。我们是否希望它们安全:通常我们不想为安全性支付运行时成本。
      • @Martin:真的取决于容器的作者。您不能使用任何标准迭代器越过末尾,但 MyContainerXXXYYY 完全可以定义 STL 样式的迭代器,如果在其控制容器的末尾递增时不会导致未定义的行为。
      【解决方案4】:

      使用得当,迭代器非常有用。
      因此,“C++ 迭代器是否安全”这个问题将取决于它的使用方式。
      请注意,不正确地使用 printf API 可能会导致严重错误。 该实现是否可以安全使用。

      【讨论】:

        【解决方案5】:

        您要问的是std::list::iterator 是否进行边界检查。答案是否定的,它没有。这意味着迭代器比其他方法更快。如果你想要边界检查,那么你可以用你自己的边界检查迭代器包装器来包装迭代器。

        但是,如果您在使用迭代器时遵循约定,那么您将始终知道在编译时何时迭代器无效,即指向无效位置。例如:

        • 当您从 std::list 擦除元素时,请确保存储迭代器 erase() 返回以获取指向新的有效位置的有效迭代器,就在被擦除的元素之外。
        • 当您调用 std::remove() 时,请确保存储返回的迭代器,以便了解容器的新边界。

        这种方法将边界检查问题搁置一旁,同时保留了迭代器的性能,无需费心确保用户不会误伤自己。

        【讨论】:

        • 实际上在末尾递增是安全的,无需任何额外开销。
        • 如果您在运行时创建容器,那么您将支付额外的检查费用,这是没有办法的。它需要额外检查递增/递减和/或取消引用。您可能会说,与性能无关,但标准 C++ 库是一个通用库,因此高效是有原因的。
        • @wilhelmtell:不是为了一个列表。您可以使最后一个元素的“下一个”指针指向它自己,因此将迭代器递增到它会使您留在原地,无需任何检查。一个实现也可以使用循环列表,所以递增 end 返回开始,再次没有检查。
        • 将列表增量的最后一个迭代器返回到自身不是边界检查。事实上,我更喜欢最后一个迭代器递增到无效节点并崩溃,因为这样我就知道错误在哪里。与在我的代码中引入静默错误相反。在我看来,一个没有段错误但有静默错误的“安全”程序并不安全。
        • 安全不仅仅是边界检查。例如,一个安全的迭代器会检查(显然是在运行时)它是否与另一个列表中的迭代器进行比较。
        【解决方案6】:

        必须测试是否it != list.end(),如果到达则退出循环。

        【讨论】:

          【解决方案7】:

          没有。如果取消引用“过去的”迭代器,则会得到未定义的行为。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-12-12
            • 2023-03-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-18
            • 2011-04-15
            • 1970-01-01
            相关资源
            最近更新 更多