使用迭代器将数组分割为具有不等大小的部分 [英] Using an iterator to Divide an Array into Parts with Unequal Size

查看:262
本文介绍了使用迭代器将数组分割为具有不等大小的部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数组,我需要分成3个元素的子数组。我想用迭代器这样做,但我最终迭代超过数组的结尾和segfaulting ,即使我不解引用迭代器。给定: auto foo = {1,2,3,4,5,6,7,8,9,10};

I have an array which I need to divide up into 3-element sub-arrays. I wanted to do this with iterators, but I end up iterating past the end of the array and segfaulting even though I don't dereference the iterator. given: auto foo = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; I'm doing:

auto bar = cbegin(foo);

for (auto it = next(bar, 3); it < foo.end(); bar = it, it = next(bar, 3)) {
    for_each(bar, it, [](const auto& i) { cout << i << endl; });
}

for_each(bar, cend(foo), [](const auto& i) { cout << i << endl; });

现在我可以通过定义完成迭代器:

Now I can solve this by defining a finish iterator:

auto bar = cbegin(foo);
auto finish = next(cend(foo), -(size(foo) % 3));

for (auto it = next(bar, 3); it != finish; bar = it, it = next(bar, 3)) {
    for_each(bar, it, [](const auto& i) { cout << i << endl; });
}

for_each(bar, finish, [](const auto& i) { cout << i << endl; });
for_each(finish, cend(foo), [](const auto& i) { cout << i << endl; });

但是,当我不解引用迭代器时,这似乎是不必要的。为什么我不能做第一个版本?

But this seems unnecessary when I don't dereference the iterator. Why can't I do the first version?

推荐答案

=http://stackoverflow.com/questions/37209725/are-iterators-past-the-one-past-the-end-iterator-undefined-behavior>迭代器是否超过一个过去端

The reason this is prohibited is covered well at your other question Are iterators past the "one past-the-end" iterator undefined behavior? so I'll just address improved solutions.

对于随机访问迭代器(如果你使用<$ c $,你必须拥有它)

For random-access iterators (which you must have if you are using <), there's no need whatsoever for the expensive modulo operation.

显着点是:


  • it + stride it 附近


  • end() - stride code> end() - it 总是合法的

  • it + stride fails when it nears the end
  • end() - stride fails if the container contains too few elements
  • end() - it is always legal

改变 it + stride< end()变成法律形式(从两边减去 it )。

From there, it's simple algebraic manipulation to change it + stride < end() into a legal form (subtract it from both sides).

最后的结果,我用了很多次:

The final result, which I have used many times:

for( auto it = c.cbegin(), end = c.cend(); end - it >= stride; it += stride )

如果内存模型是平坦的 - C ++行为的限制不适用于预期计算的 end-stride * sizeof(* it)编译器将C ++转换为原始操作。

The compiler is free to optimize that back to comparison to a precomputed end - stride * sizeof(*it) if the memory model is flat -- the limitations of C++ behavior don't apply to the primitive operations which the compiler translates C++ into.

你可以使用 std :: distance(it,end)如果你喜欢使用命名的函数而不是运算符,但是这将只对随机访问迭代器有效。

You may of course use std::distance(it, end) if you prefer to use the named functions instead of operators, but that will only be efficient for random-access iterators.

要使用forward iterator,结合递增和终止条件,如

For use with forward iterators, you should use something that combines the increment and termination conditions like

struct less_preferred { size_t value; less_preferred(size_t v) : value(v){} };

template<typename Iterator>
bool try_advance( Iterator& it, less_preferred step, Iterator end )
{
     while (step.value--) {
         if (it == end) return false;
         ++it;
     }
     return true;
}

对于这种额外的重载,你将获得随机访问迭代器的高效行为:

With this additional overload, you'll get efficient behavior for random-access iterators:

template<typename RandomIterator>
auto try_advance( RandomIterator& it, size_t stride, RandomIterator end )
     -> decltype(end - it < stride) // SFINAE
{
     if (end - it < stride) return false;
     it += stride;
     return true;
}

这篇关于使用迭代器将数组分割为具有不等大小的部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆