繁体   English   中英

为什么从采用std :: ranges :: output_range的算法返回std :: ranges :: safe_iterator_t而不是std :: ranges :: safe_subrange_t

[英]Why return std::ranges::safe_iterator_t instead of std::ranges::safe_subrange_t from algorithms taking std::ranges::output_range

我正在编写一种算法,该算法将一些数据写入提供的输出范围(问题的初始文本包括具体内容,并将注释中的讨论变成错误的方向)。 我希望它在API中与标准库中的其他范围算法尽可能接近。

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

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

我找到了P0970 ,它看起来像稍后添加了std::ranges::safe_subrange_t 也许算法根本没有更新? 还是有其他原因?

范围设计中是否存在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中)来简洁地组成多个操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM