12

Is it allowed to increment an iterator variable it that already is at end(), i.e. auto it = v.end()?

  • Is it allowed in general?
  • If not, is it not allowed for vector?
  • If yes, is ++it maybe idempotent if it==v.end()?

I ask, because I stumbled upon code like this:

std::vector<int> v{ 1, 2, 3, 4, 5, 6, 7 };
// delete every other element
for(auto it=v.begin(); it<v.end(); ++it) { // it<end ok? ++it ok on end?
  it = v.erase(it);
}

It works fine with g++-6, but that is no proof.

For one it<v.end() may only work with vectors, I suppose it should read it!=v.end() in general. But in this example that would not recognize the end of v if ++it is applied when it already is on the end.

towi
  • 21,587
  • 28
  • 106
  • 187
  • Using `!=` will achieve the same effect as `<`, minus the whole smaller than part... – user2296177 Oct 02 '16 at 18:13
  • @LightnessRacesinOrbit oh, you mean because I only delete every second element? No, that is by design. But you are right, I should have mentioned that. As it stands like now it looks broken, I agree. I'll add a code comment. – towi Oct 03 '16 at 09:29
  • Oh I see that's deliberate – Lightness Races in Orbit Oct 03 '16 at 09:35
  • 1
    @LightnessRacesinOrbit yeah. some smart#$5§ way of doing special stuff... I hate that, too, if there is no comment. – towi Oct 03 '16 at 09:37
  • 3
    Possible duplicate of [What happens if you increment an iterator that is equal to the end iterator of an STL container](https://stackoverflow.com/questions/1057724/what-happens-if-you-increment-an-iterator-that-is-equal-to-the-end-iterator-of-a) – Raedwald Nov 29 '17 at 11:05

1 Answers1

20

No the behaviour is undefined. You are allowed to set an iterator to end(), but you must not increment it or dereference it.

You are allowed to decrement it so long as the backing container is not empty.

JFMR
  • 23,265
  • 4
  • 52
  • 76
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    From the working draft, it seems that you can increment an iterator how many times you want as long as you don't dereference it. It's valid for both input and output iterators, thus all the ones that _derives_ from them (as an example forward iterator). I'd rather say that to increment the iterator is not UB unless you decide to dereference those iterators. – skypjack Oct 02 '16 at 20:29
  • The iterator of a vector must met the requirements of a forward iterator. The forward iterator must satisfy the requirements of the input iterator. The input iterator can be incremented and it must assure that `i++` returns an iterator that you can dereference or that is past the end. Thus `i++` seems not to be an UB. Note that incrementing a pointer is not an UB as well, the problem can arise when you dereference it. – skypjack Oct 03 '16 at 05:40
  • 3
    "Note that incrementing a pointer is not an UB as well". That is not correct. You're only allowed to increment pointers in situations where pointer arithmetic is valid (e.g. arrays, one past an array and one past a scalar). – Bathsheba Oct 03 '16 at 06:55
  • Bathsheba is right, @skypjack. It is a common misconception that you can do whatever you like to a pointer as long as you don't dereference it, cos it's "just a memory address", right? Wrong! As for iterators, I don't know which "working draft" you're referring to (state a document number please; there are a _lot_ of documents you could be talking about) but in C++14 proper most Iterator types must be dereferenceable as a postcondition to `++`; not all (e.g. Output iterators don't need to be) but Bidirectional ones _do_ (e.g. table 110). – Lightness Races in Orbit Oct 03 '16 at 09:48
  • @LightnessRacesinOrbit Actually I'm referring to the standard, not to a common idea. Maybe I'm misreading it, but anyway... [This](http://eel.is/c++draft/) is the working draft I'm referring to. – skypjack Oct 03 '16 at 09:54
  • @skypjack: Then you're interpreting the standard incorrectly :) Check out http://eel.is/c++draft/expr.add#4 In short, via increment/decrement you cannot well-definedly obtain a pointer to a non-existent thing. I think the only way you can "safely" get arbitrary pointers (e.g. memory mapped whatsits) is to initialise them to a specific value then leave them. Whether you dereference them is immaterial. – Lightness Races in Orbit Oct 03 '16 at 09:55
  • @LightnessRacesinOrbit Fair enough. I'll look over it in the evening and I'll be back if needed. Thank you. ;-) – skypjack Oct 03 '16 at 09:59
  • @skypjack: npsssss :) – Lightness Races in Orbit Oct 03 '16 at 10:00
  • @LightnessRacesinOrbit I read it (not exactly the evening here, anyway). I see what you say, but does the standard say that the iterator of the vector is a pointer? Ok, that's the logic implementation, but I found only that it must fulfill the requirements of a forward iterator and incrementing it is not an UB, right? I'm sure you are right, but am I missing here? Where does the standard say that? (Just curios, of course). – skypjack Oct 03 '16 at 15:53
  • @skypjack: You're conflating two issues - just look up the requirements for the iterator category you're interested in – Lightness Races in Orbit Oct 03 '16 at 16:25
  • @BathSheba is the same true for rend() function as well? – kapil Feb 02 '20 at 11:36