繁体   English   中英

迭代器的std :: distance差于RandomAccessIterator

[英]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_typeiterator ),我使用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++从获得firstlast

由于仅随机访问迭代器提供+和-运算符,因此该库提供了两个功能模板advancedistance 这些函数模板将+-用于随机访问迭代器(因此,它们的时间恒定)。 对于输入,正向和双向迭代器,它们使用++提供线性时间实现。

[N4431§24.4.4/ 1]

在您链接的文档中,“如果InputIt不是RandomAccessIterator ,那么如果无法通过(可能重复地) first递增而无法从first到达last行为,则该行为是不确定的”。

未定义的行为并不意味着访问冲突。 它意味着一切,包括返回一些正数。

暂无
暂无

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

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