Alex
Alex

Reputation: 1175

Iterator end check fails after incrementing inside a `for` loop

This question is very likely to be a duplicate, but I have not found anything on this issue.

Why can incrementing an iterator placed at the last position in a vector make it not equal to vector.end()?

Or, in other words, why does this execute normally:

int main() {
    vector<string> vec = {"ve"};

    for (auto it = vec.begin(); it != vec.end(); it++) {}

    return 0;
}

While this one goes into an infinite loop:

int main() {
    vector<string> vec = {"ve"};

    for (auto it = vec.begin(); it != vec.end(); it++) { it++; }

    return 0;
}

And this one:

int main() {
    vector<string> vec = {"ve"};

    for (auto it = vec.begin(); it != vec.end(); it++) {
        cout << (it == vec.end()) << " ";
        cout << (*it == "ve") << endl;
        it++;
    }

    return 0;
}

causes a SEGFAULT having printed:

0 1
0

so, it, in fact, was incremented, so that its contents became empty (optimised out, according to the debugger), but it did not become equal to vec.end(). Why?

Upvotes: 3

Views: 1378

Answers (3)

Tim B
Tim B

Reputation: 41168

You are checking for it != vec.end() but with it++ happening twice you are skipping twice on each check. In other words you are running past the end of the vector without spotting it.

If you add one more element to your vector then the loop will hit the end and stop as you will no longer skip the end point (obviously this is not a "proper" fix, it just demonstrates the problem).

To fix it check for end before the increment in the loop. You could also check using operator< in the conditional but that's a little risky as you're leaving an invalid it for a while which is bad for future maintenance of the code.

Upvotes: 4

pathankhan.salman
pathankhan.salman

Reputation: 54

In a for loop, the increment operation on the iterator is the last (and implicit) operation in a cycle.

Case 1: Loop begins with "it" = vec.begin(). Nothing happens. "it" is incremented (implicit). it = vc.end(). Loop ends. Hence the normal behavior.

Case 2: Loop begins with it = vec.begin(). "it" is incremented. it = vc.end(). "it" is incremented again (implicit). "it" moves to the next memory location, and keeps increasing in every cycle. Hence the infinite loop.

Case 3: Loop begins with it = vec.begin(). Check performed if it == vc.end(). Return false. Value in the memory location referenced by "it" is printed. "it" is incremented. it = vc.end(). "it" is incremented again (implicit). "it" moves to the next memory location, which is unallocated. Hence the SEG fault.

Upvotes: 1

cadaniluk
cadaniluk

Reputation: 15229

Imagine it pointing to one before vec.end(), supposedly the last iteration of the for loop.

  1. it != vec.end(); will be true, so the loop will continue.
  2. it++; in the body is executed. it == vec.end() now.
  3. it++ from the for loop head is executed. it points one beyond vec.end().

vec.end() points one beyond the last element of vec, which is still well-defined. vec.end() + 1 (the final value of it) points two beyond the last element of vec, which is undefined behavior.

That means that dereferencing the iterator accesses unallocated memory (explaining the segmentation fault). Undefined behavior again.

Upvotes: 5

Related Questions