我最近审核了不久前实施的algorithm并发现,it can be improved不仅可以在RandomAccessIterator输入范围上运行,还可以在ForwardIterator上运行(多通保证3} em>仍然是要求)。
我决定通过修改代码中的所有位置(当前使用迭代器之间的简单差异)来简单地降级需求,而不是使用std::distance
。 std::distance
algorithm described here。由于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;
哈希函数来实现简单差异h(lhs - rhs)
(实际上 xor 哈希值的组合,但这里不重要)对于某些固定的iterator lhs
和一些变化的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
始终返回非负数。
它是未定义的行为还是允许将std::distance
应用于任何一对ForwardIterator-s? -stdlib=
为libc++
。
答案 0 :(得分:2)
[......]是否可以将
std::distance
用于任何一对ForwardIterator
- s?
如果你想坚持标准,那么显然不,不允许:
template <class InputIterator> typename iterator_traits<InputIterator>::difference_type distance( InputIterator first, InputIterator last);
[...] 要求:如果
InputIterator
符合随机访问迭代器的要求,则last
可以访问first
,或first
可以访问last
;否则,last
可以从first
到达。[N4431§24.4.4/ 5]
原因是对于前向迭代器,该函数重复应用operator++
从first
到last
:
由于只有随机访问迭代器提供了+和 - 操作符,因此该库提供了两个函数模板
advance
和distance
。这些函数模板使用+
和-
作为随机访问迭代器(因此,它们是常量时间);对于输入,转发和双向迭代器,它们使用++
来提供线性时间实现。[N4431§24.4.4/ 1]
答案 1 :(得分:2)
从您关联的文档&#34;如果InputIt
不是RandomAccessIterator
,如果last
无法从first
到达(可能重复),则行为未定义递增first
&#34;。
未定义的行为并不意味着访问违规;它意味着什么,包括返回一些正数。