我正在编写一种算法,该算法将一些数据写入提供的输出范围(问题的初始文本包括具体内容,并将注释中的讨论变成错误的方向)。我希望它在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
对象本身已销毁,进入字符串 View 的迭代器仍然可以使用。那是因为string_view
只是引用内存中其他位置的元素,而string_view
对象本身不包含任何额外的状态。反例将是任何一个容器。例如std::vector
,它拥有其元素,以及C++ 20的std::ranges
命名空间中的许多 View ,其中大多数包含附加状态(例如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和调用约定,返回指针(例如,找到的位置)比返回包含两个指针的结构(例如,找到的位置和范围的结尾)更有效。
相反,我们使用更高级别的 View (和 Action ,在range-v3中)来简洁地组成多个操作。
关于c++ - 为什么从采用std::ranges::output_range的算法返回std::ranges::safe_iterator_t而不是std::ranges::safe_subrange_t,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57860924/