【问题标题】:Should I allow my custom iterator to go past the end?我应该允许我的自定义迭代器结束吗?
【发布时间】:2018-01-05 14:57:41
【问题描述】:

我正在为基于索引的类实现迭代器。有一个最大有效值;我的问题是当客户端代码使迭代器超出我的end() 值时该怎么办:

  • operator++() 是否应该始终检查我没有超过结尾?或者
  • operator*() 是否应该始终检查我没有超过末尾,而迭代器可以(无用地)前进或移动到末尾?

请解决一个非调试设置,在该设置中我不能确定愚蠢的开发人员不会尝试将他们的指针推进到末尾。

【问题讨论】:

  • 一般来说,至少在调试版本中进行检查是个好主意。并且两个函数都应该有验证,因为你不能在最后取消引用迭代器。
  • 我会 assert() 这些支票。
  • @Phil1970:好的,但请参阅编辑。
  • @melpomene:好的,但请参阅编辑。
  • 刚刚在源代码周围徘徊,我见过的所有实现都没有。基本上,一旦你增加了结束,所有的赌注都结束了。虽然我同意其他 cmets - 我倾向于在调试版本中断言。

标签: c++ iterator idioms


【解决方案1】:

我所做的是在编译调试版本时添加严格的检查代码,并删除对代码发布版本的这些检查。

我广泛使用assert(或类似的)。它会执行运行时检查除非您使用定义的宏 NDBUG 进行编译,在这种情况下检查会完全消除。

STL 理念本身应该提供一种安全措施,因为迭代器限制通常来自安全的地方。

当您运行一个算法时,您通常会从这样的容器中获取边界:

std::vector<int> v {1, 2, 3, 4};

do_some_stuff(std::begin(v), std::end(v));

否则你可能会得到你的迭代器作为算法的结果:

auto found_iter = std::find(std::begin(v), std::end(v));

这使得使用迭代器非常安全。当您开始使用迭代器 athematic 时,它会变得有点危险:

auto dangerous_iter = std::begin(v) + 5; // not encouraged 

但是应该在调试阶段使用assert 和类似方法来捕获错误。

要记住的另一点是,如果您通过运行时检查使迭代器“安全”,您最终可能会在代码中隐藏错误。因为这样的运行时检查应该会导致一个可见的奇观,比如异常,不要只是默默地什么都不做。

【讨论】:

    【解决方案2】:

    是的,不要在任何地方进行范围检查。

    基于@MalcolmMclean 的回答:由于 C++ 标准没有定义迭代器在超出范围末尾时的行为,因此客户端代码的问题是确保它不会那样做——不是你的。所以当你不调试时,不要为了范围检查而牺牲性能,只要假设你没有超过终点。

    当您正在为调试而编译时,正如@Phil1970 所建议的,使用抛出异常或使用断言的范围检查可能是个好主意。

    【讨论】:

      【解决方案3】:

      没关系。

      为了符合 STL 约定,您需要一个 begin() 方法,该方法将迭代器返回到集合的开头,以及一个 end() 方法,该方法将迭代器返回到最后一个元素之后的位置。因此,前进到 end() 并比较是否相等是明确定义的。然而,超越 end() 并没有明确定义。最好抛出错误,但不是必需的,尤其是在涉及其他冗余检查的情况下。如果人们没有正确使用迭代器,您不对任何错误负责。

      【讨论】:

      • 它没有明确定义的事实并不一定意味着它应该对于特定的迭代器是未定义的。或者 - 您是否建议如果客户端代码超过末尾,我应该让客户端代码自行其是?我想这是一个有效的选择。
      • @einpoklum - 未定义的行为只是拥有狭窄 API 合约的另一种说法。通过只同意一个狭窄的合同(“使用不当,风险自负”),您可以提供不受冗余检查困扰的代码。迭代器是一种非常常见的模式,以及它们在 C++ 标准库中的使用,老实说,我不认为任何人错误地使用迭代器的风险太大。
      • @einpoklum - 此外,一个狭窄的合同总是可以扩大。倒不如说是……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      • 2022-11-07
      • 2011-09-22
      • 2021-02-17
      • 1970-01-01
      • 2018-11-16
      相关资源
      最近更新 更多