![](/img/trans.png)
[英]Why do std range algorithms return std::ranges::dangling for rvalue arguments instead of… well, just working?
[英]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
可以归结为两点:
对于(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::fill
和ranges::generate
逻辑相同。
那么,为什么不返回safe_subrange_t
而不是safe_iterator_t
呢? 这会使算法与其他算法完美组合吗?
它会! 但是它将返回到他们已经拥有的呼叫者信息。 即,范围末端的位置。 在算法中,我们避免做不必要的工作以使它们尽可能高效。 给定ABI和调用约定,返回指针(例如,找到的位置)比返回包含两个指针(例如,找到的位置和范围的结尾)的结构更有效。
相反,我们使用更高级别的视图(和动作,在range-v3中)来简洁地组成多个操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.