【问题标题】:Why return std::ranges::safe_iterator_t instead of std::ranges::safe_subrange_t from algorithms taking std::ranges::output_range为什么从采用 std::ranges::output_range 的算法中返回 std::ranges::safe_iterator_t 而不是 std::ranges::safe_subrange_t
【发布时间】:2020-01-11 15:05:20
【问题描述】:

我正在编写一种算法,该算法将一些数据写入提供的输出范围(问题的初始文本包括细节,并且将 cmets 中的讨论转向了错误的方向)。我希望它在 API 中尽可能接近标准库中的其他范围算法。

我查看了std::ranges::output_range 实例的最新草案,发现只有两种算法:

他们都返回std::ranges::safe_iterator_t。我认为返回std::ranges::safe_subrange_t 是合乎逻辑的。即使您写入输出流,您仍然可以在这种情况下返回一个迭代器-哨兵对并将该范围向下传递。

我找到了P0970,看起来std::ranges::safe_subrange_t 是后来添加的。也许算法根本没有更新?还是有别的原因?

【问题讨论】:

  • 什么是“Unicode标量值”?
  • 也许你应该提供一个你正在尝试做的例子。
  • 那与一系列代码单元有什么不同呢?您设想的转换类型是什么?
  • @Lyberta:算法不适用于operator|。这是一个根本不同的功能,由范围操作等管理......它们 not 是 Ranges TS 的一部分。它们最终可能会被标准化,但它们不是 C++20 的一部分。

标签: c++ iterator range c++20


【解决方案1】:

safe_iterator_t 在范围设计中的存在可归因于两件事:

  1. 一些算法将迭代器返回到传递给算法的范围内,并且
  2. 有些范围的迭代器比它们的范围寿命更长,而有些则没有。

对于 (2),示例可能是 std::string_view。即使在 string_view 对象本身已被销毁之后,进入字符串视图的迭代器仍然可以使用。那是因为string_view 只是引用内存中其他地方的元素,而string_view 对象本身不包含额外的附加状态。反例是任何容器;例如,std::vector,它拥有自己的元素,以及 C++20 的 std::ranges 命名空间中的许多视图,其中大部分包含附加状态(例如,views::filter 的谓词)。

将上面的两个项目符号放在一起,现在考虑像find 这样的函数(简化):

template <input_range R, class T>
  requires ...
safe_iterator_t<R> find(R && rg, const T & val);

此函数返回一个迭代器到rg 范围内,但如果rg 是一个右值,那么它可能会在函数返回时被删除。这意味着返回的迭代器几乎肯定是悬空的。

safe_iterator_t 检查R 是否是迭代器可以安全地超过该范围的那些特殊范围类型之一。如果是这样,您只需将迭代器取回,不要大惊小怪。如果不是,则此函数返回一个名为std::ranges::dangling 的特殊类型的空对象。这是为了让你明白,你需要在这里更深入地思考生命。

同样的逻辑也适用于采用输出范围的算法,例如 ranges::fillranges::generate

您可能会问,为什么不返回safe_subrange_t 而不是safe_iterator_t?这不是让算法与其他算法很好地组合吗?

会的! 但是会返回给他们已经拥有的调用者信息;即范围结束的位置。在算法中,我们避免做不必要的工作以使它们尽可能高效。给定 ABI 和调用约定,返回一个指针(例如,找到的位置)比返回一个包含两个指针(例如,找到的位置和范围的结尾)的结构更有效。

相反,我们使用更高级别的视图(以及 range-v3 中的操作)来简洁地组合多个操作。

【讨论】:

  • 如果通过了拥有临时性,为什么不直接编译失败?
  • 好问题。你是对的,在find 的情况下,这可能是一个更好的答案。还有其他算法会返回几条信息,在这种情况下,safe_iterator_t 用于仅编辑掉线位。我们本可以决定将返回 just safe_iterator_t 的算法与返回带有 dangly 成员的结构的算法区别对待,但没有人为此争论,所以我们在这里。
  • 我猜,尝试使用dangling 代替普通迭代器将无法编译,因此无论如何都会出现编译错误,距离代码中的损坏位置更远。
猜你喜欢
  • 2021-05-11
  • 2021-02-18
  • 2020-09-22
  • 2021-10-01
  • 2020-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多