-1

Here is a piece of my code:

vector<int> v {1, 2, 10, 4, 5, 6, 7, 8, 9 };
for (auto i = v.begin(); i != v.end(); i = i + 2) {
    cout << (*i) << " ";
}

What I want to do is to advance the iterator by 2 elements after each iteration. However, there is a runtime exception: offset out of range. So my question is:

Is there a way to iterate by 2 elements each time with a for loop and if possible, can the condition to prevent this exception be defined in the for() statement?

allicanseenow
  • 123
  • 1
  • 10
  • 4
    Change `i != v.end();` to `i < v.end();` – user0042 Aug 09 '17 at 15:29
  • 3
    just think about what happens if your vector contains an odd number of entries (it does). Will `it != v.end()` ever be false ? – 463035818_is_not_an_ai Aug 09 '17 at 15:30
  • 1
    btw I would always use a index based loop instead of an iterator based loop when you do care about the index. Iterators arent really meant to be treated like indexes – 463035818_is_not_an_ai Aug 09 '17 at 15:32
  • @user0042 wouldn't it still be UB to increment an iterator to the last element by 2? e.g. `(v.end()-1)+2` – Kevin Aug 09 '17 at 15:40
  • @Kevin No, dereferencing it after is UB. – user0042 Aug 09 '17 at 15:49
  • @user0042 Looks like getting an iterator past the end (`v.end()+1`) is UB: https://stackoverflow.com/questions/37209725/are-iterators-past-the-one-past-the-end-iterator-undefined-behavior – Kevin Aug 09 '17 at 15:54
  • @Kevin And you read this [answer](https://stackoverflow.com/a/37219916/8242698) too? – user0042 Aug 09 '17 at 15:57
  • @user0042 Yes, and it tells me that incrementing `v.end()` violates the precondition that the iterator is dereferenceable, i.e. it's UB. From the "operational semantics" it seems that `i+2`, when `i == v.end()-1` is also UB. – Kevin Aug 09 '17 at 16:01
  • Possible duplicate of [Using an iterator to Divide an Array into Parts with Unequal Size](https://stackoverflow.com/questions/36425393/using-an-iterator-to-divide-an-array-into-parts-with-unequal-size) – Jonathan Mee Aug 09 '17 at 16:27

2 Answers2

0

Is there a way to iterate by 2 elements each time with a for loop and if possible, can the condition to prevent this exception be defined in the for() statement?

Sure there is a way. The most natural would be this

vector<int> v {1, 2, 10, 4, 5, 6, 7, 8, 9 };
for (size_t i=0; i < v.size(); i = i + 2) {
    cout << v[i] << " ";
}

Iterators (just like anything else) arent the best tool for every situation. Iterators are meant to be an abstraction that does not care about an index. Thus when you actually do care about the index, I would not use iterators, but a plain index based loop. Of course its a matter of taste, but being so much used to loops that go from begin to end incremented via ++it, it can help a lot to distinguish a loop that deviates from this usual pattern.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

As @tobi303 said, the most suitable way for you is to use indexes and not iterators. Anyway, there's a reason for the Out of Range Exception. If you try with this vector (or in general if you add another element to it):

{1, 2, 10, 4, 5, 6, 7, 8, 9, 1 }

You won't obtain that exception. This is what the doc says about the end method:

Returns an iterator referring to the past-the-end element in the vector container. The past-the-end element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced.

So, when *i is equal to 9, and the for loop checks for the end of the vector, it will go on. But if you add 2 to i, the end method will never match the actual end.

Marco Luzzara
  • 5,540
  • 3
  • 16
  • 42