简体   繁体   English

迭代器的std :: distance差于RandomAccessIterator

[英]std::distance for iterators worse then RandomAccessIterator

I recently reviewed not long ago implemented algorithm and found, that it can be improved to be able to operate on not just only RandomAccessIterator input range, but even on ForwardIterator one ( multipass guarantee is still the requirement). 我最近查看了不久前实现的算法 ,发现它可以改进为不仅可以在RandomAccessIterator输入范围上运行,甚至可以在ForwardIterator上运行(仍然需要通道保证 )。

I decide to simply downgrade the requirement by modifying all the places in the code, that currently uses simple difference between iterators, in a way to use std::distance instead. 我决定通过修改代码中的所有位置(目前使用迭代器之间使用简单的区别)来简单地降级需求,而改为使用std::distance The std::distance algorithm described here . 这里描述std::distance 算法 Due to very nature of std::distance algorithm the modifications was not just a search and replace one, namely: 由于std::distance算法的本质,修改不只是一种搜索和替换 ,即:

  • For ordered containers internally used in the algorithm I replaced all occurences of operator < or std::less< iterator > / std::less<> with: 对于算法内部使用的有序容器,我将所有出现的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);
                   };

Say, std::set< iterator > x; 说, std::set< iterator > x; modified to be std::set< iterator, decltype(less) > x{less}; 修改为std::set< iterator, decltype(less) > x{less}; .

  • For unordered containers internally used in the algorithm ( value_type is iterator ) I use std::hash< std::intptr_t > h; 对于算法内部使用的无序容器( value_typeiterator ),我使用std::hash< std::intptr_t > h; hash function for simple difference h(lhs - rhs) (actually xor combination of hash values, but it not matters here) for some fixed iterator lhs and a number of varying iterator rhs . 对于某些固定iterator lhs和许多可变iterator rhs简单差分h(lhs - rhs) (实际上是哈希值的异或组合,但在这里并不重要)的哈希iterator rhs It modified to be h(std::distance(lhs, rhs)) . 修改为h(std::distance(lhs, rhs))

The former point is correct, but the latter is evidently no. 前一点是正确的,但后者显然不是。 Due to rhs can be unrecheable from lhs just only by means of simple incrementation and there is no way to know what to do a priori: to increment lhs to reach rhs or to increment rhs to reach lhs . 由于rhs只能通过简单的递增而无法从lhs ,因此无法知道先验如何做:递增lhs达到rhs或递增rhs达到lhs

But above hash still works. 但以上哈希仍然有效。 It is strange... because sometimes, when lhs > rhs (in some sense), there should be access violation (sometimes). 这很奇怪……因为有时候,当lhs > rhs (在某种意义上)时,应该出现访问冲突(有时)。 Say, if: 说,如果:

std::list< int > input{1, 2, 3, 4};
auto a = std::begin(input), b = std::next(lhs, 2);

then increments, contained into std::distance(b, a) , should never stop and eventually reaches boundary of not yet allocated memory page. 然后,包含在std::distance(b, a)增量将永远不会停止,并最终到达尚未分配的内存页的边界。 But AV never happens in my program. 但是AV永远不会在我的程序中发生。 std::distance always return non-negative number. std::distance始终返回非负数。

Is it undefined behaviour or is it permittable to apply std::distance for any pair of ForwardIterator-s? 它是未定义的行为,还是允许对任何ForwardIterator-s应用std::distance The -stdlib= is libc++ . -stdlib=libc++

[...] is it permittable to apply std::distance for any pair of ForwardIterator -s? [...]是否可以对任何ForwardIterator -s对应用std::distance

If you want to stick to the standard, then clearly no, it's not permitted : 如果您要遵守标准,那么显然不可以,这是不允许的

 template <class InputIterator> typename iterator_traits<InputIterator>::difference_type distance( InputIterator first, InputIterator last); 

[...] Requires: If InputIterator meets the requirements of random access iterator, last shall be reachable from first or first shall be reachable from last ; [...]要求:如果InputIterator满足随机访问迭代器的要求,则last应该是从first first可访问的,或者first应该是从last可以访问的; otherwise, last shall be reachable from first . 否则, last应该从first到达

[N4431 §24.4.4/5] [N4431§24.4.4/ 5]

The reason is that for forward iterators the function is repeatedly applying operator++ to get from first to last : 原因是,对于前向迭代器的功能是重复应用operator++从获得firstlast

Since only random access iterators provide + and -operators, the library provides two function templates advance and distance . 由于仅随机访问迭代器提供+和-运算符,因此该库提供了两个功能模板advancedistance These function templates use + and - for random access iterators (and are, therefore, constant time for them); 这些函数模板将+-用于随机访问迭代器(因此,它们的时间恒定)。 for input, forward and bidirectional iterators they use ++ to provide linear time implementations. 对于输入,正向和双向迭代器,它们使用++提供线性时间实现。

[N4431 §24.4.4/1] [N4431§24.4.4/ 1]

From the documentaton you linked "If InputIt is not RandomAccessIterator , the behavior is undefined if last is not reachable from first by (possibly repeatedly) incrementing first ". 在您链接的文档中,“如果InputIt不是RandomAccessIterator ,那么如果无法通过(可能重复地) first递增而无法从first到达last行为,则该行为是不确定的”。

Undefined behaviour does not mean an access violation; 未定义的行为并不意味着访问冲突。 it means anything at all, including returning some positive number. 它意味着一切,包括返回一些正数。

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

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