Home > Enterprise >  Iterators invalidation
Iterators invalidation

Time:01-13

Hi I read in C primer that adding elements to a vector invalidates the iterators. I don't understand why deleting elements doesn't invalidate them as the following code works

std::vector<int> a = {1,2,3,4,5,6};

auto b = a.begin();

while (b != a.end()){
    
    if (*b%2 != 0)
        a.erase(b);
    else
        b  ;
}

NOTE: This code if from C primer itself and cpp reference as well

CodePudding user response:

Not actually an answer to the question, but I think it is worth mentioning that in modern C you should try to avoid iterators by using algorithms and range-based for loops. In this particular case use std::erase_if:

std::vector<int> a = {1,2,3,4,5,6};
std::erase_if(a, [](int x) { return x%2 != 0; });

CodePudding user response:

In general this code snippet

auto b = a.begin();

while (b != a.end()){
    
    if (*b%2 != 0)
        a.erase(b);
    else
        b  ;
}

is invalid. It works because the container std::vector satisfies the concept of contiguous ranges. If instead of the vector you will use for example std::list<int> when the iterator b will be invalid.

It would be correctly to write

auto b = a.begin();

while (b != a.end()){
    
    if (*b%2 != 0)
        b = a.erase(b);
    else
        b  ;
}

CodePudding user response:

Common idiom. From cppreference: (erase) 'Invalidates iterators and references at or after the point of the erase, including the end() iterator.

Others have pointed out it should be written like this:

#include <vector>

std::vector<int> vec = { 1, 2, 3, 4 };

for (auto it = vec.begin(); it != vec.end(); )
{
    if (*it % 2 != 0)
    {
        it = vec.erase(it);
    }
    else
    {
         it;
    }
}

Adjust if one prefers 'while' over 'for'. If performance is paramount one can start from the end though this may be less cache friendly.

Edit: code snippet is literally the cppreference link.

CodePudding user response:

Adding elements to a vector may lead to a complete reallocation of the vector. This invalidates all iterators held previously.

If you delete an entry of the vector the erase method returns: a) a iterator to the next valid element b) the end iterator.

But you have to use it. In your case:

b = a.erase(b);
  • Related