[英]std::distance for iterators worse then RandomAccessIterator
我最近查看了不久前实现的算法 ,发现它可以改进为不仅可以在RandomAccessIterator输入范围上运行,甚至可以在ForwardIterator上运行(仍然需要多通道保证 )。
我决定通过修改代码中的所有位置(目前使用迭代器之间使用简单的区别)来简单地降级需求,而改为使用std::distance
。 这里描述的std::distance
算法 。 由于std::distance
算法的本质,修改不只是一种搜索和替换 ,即:
operator <
或std::less< iterator >
/ std::less<>
替换为: auto const less = [ibeg = std::cbegin(input)] (iterator const & l, iterator const & r)
{
return std::distance(ibeg, l) < std::distance(ibeg, r);
};
说, std::set< iterator > x;
修改为std::set< iterator, decltype(less) > x{less};
。
value_type
为iterator
),我使用std::hash< std::intptr_t > h;
对于某些固定iterator lhs
和许多可变iterator rhs
简单差分h(lhs - rhs)
(实际上是哈希值的异或组合,但在这里并不重要)的哈希iterator rhs
。 修改为h(std::distance(lhs, rhs))
。 前一点是正确的,但后者显然不是。 由于rhs
只能通过简单的递增而无法从lhs
,因此无法知道先验如何做:递增lhs
达到rhs
或递增rhs
达到lhs
。
但以上哈希仍然有效。 这很奇怪……因为有时候,当lhs > rhs
(在某种意义上)时,应该出现访问冲突(有时)。 说,如果:
std::list< int > input{1, 2, 3, 4};
auto a = std::begin(input), b = std::next(lhs, 2);
然后,包含在std::distance(b, a)
增量将永远不会停止,并最终到达尚未分配的内存页的边界。 但是AV永远不会在我的程序中发生。 std::distance
始终返回非负数。
它是未定义的行为,还是允许对任何ForwardIterator-s应用std::distance
? -stdlib=
是libc++
。
[...]是否可以对任何
ForwardIterator
-s对应用std::distance
?
如果您要遵守标准,那么显然不可以,这是不允许的 :
template <class InputIterator> typename iterator_traits<InputIterator>::difference_type distance( InputIterator first, InputIterator last);
[...]要求:如果
InputIterator
满足随机访问迭代器的要求,则last
应该是从first
first
可访问的,或者first
应该是从last
可以访问的; 否则,last
应该从first
到达 。[N4431§24.4.4/ 5]
原因是,对于前向迭代器的功能是重复应用operator++
从获得first
到last
:
由于仅随机访问迭代器提供+和-运算符,因此该库提供了两个功能模板
advance
和distance
。 这些函数模板将+
和-
用于随机访问迭代器(因此,它们的时间恒定)。 对于输入,正向和双向迭代器,它们使用++
提供线性时间实现。[N4431§24.4.4/ 1]
在您链接的文档中,“如果InputIt
不是RandomAccessIterator
,那么如果无法通过(可能重复地) first
递增而无法从first
到达last
行为,则该行为是不确定的”。
未定义的行为并不意味着访问冲突。 它意味着一切,包括返回一些正数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.