Vector erase iterator

C++VectorIterator

C++ Problem Overview


I have this code:

int main()
{
	vector<int> res;
	res.push_back(1);
	vector<int>::iterator it = res.begin();
	for( ; it != res.end(); it++)
	{
		it = res.erase(it);
		//if(it == res.end())
		//	return 0;
	}
}

"A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the vector end if the operation erased the last element in the sequence."

This code crashes, but if I use the if(it == res.end()) portion and then return, it works. How come? Does the for loop cache the res.end() so the not equal operator fails?

C++ Solutions


Solution 1 - C++

res.erase(it) always returns the next valid iterator, if you erase the last element it will point to .end()

At the end of the loop ++it is always called, so you increment .end() which is not allowed.

Simply checking for .end() still leaves a bug though, as you always skip an element on every iteration (it gets 'incremented' by the return from .erase(), and then again by the loop)

You probably want something like:

 while (it != res.end()) {
        it = res.erase(it);    
 }

to erase each element

(for completeness: I assume this is a simplified example, if you simply want every element gone without having to perform an operation on it (e.g. delete) you should simply call res.clear())

When you only conditionally erase elements, you probably want something like

for ( ; it != res.end(); ) {
  if (condition) {
    it = res.erase(it);
  } else {
    ++it;
  }
}

Solution 2 - C++

for( ; it != res.end();)
{
    it = res.erase(it);
}

or, more general:

for( ; it != res.end();)
{
    if (smth)
        it = res.erase(it);
    else
        ++it;
}

Solution 3 - C++

Because the method erase in vector return the next iterator of the passed iterator.

I will give example of how to remove element in vector when iterating.

void test_del_vector(){
    std::vector<int> vecInt{0, 1, 2, 3, 4, 5};

    //method 1
    for(auto it = vecInt.begin();it != vecInt.end();){
        if(*it % 2){// remove all the odds
            it = vecInt.erase(it); // note it will = next(it) after erase
        } else{
            ++it;
        }
    }

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

    // recreate vecInt, and use method 2
    vecInt = {0, 1, 2, 3, 4, 5};
    //method 2
    for(auto it=std::begin(vecInt);it!=std::end(vecInt);){
        if (*it % 2){
            it = vecInt.erase(it);
        }else{
            ++it;
        }
    }

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

    // recreate vecInt, and use method 3
    vecInt = {0, 1, 2, 3, 4, 5};
    //method 3
    vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(),
                 [](const int a){return a % 2;}),
                 vecInt.end());

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

}

output aw below:

024
024
024

A more generate method:

template<class Container, class F>
void erase_where(Container& c, F&& f)
{
    c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)),
            c.end());
}

void test_del_vector(){
    std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
    //method 4
    auto is_odd = [](int x){return x % 2;};
    erase_where(vecInt, is_odd);

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;    
}

Solution 4 - C++

The it++ instruction is done at the end of the block. So if your are erasing the last element, then you try to increment the iterator that is pointing to an empty collection.

Solution 5 - C++

Something that you can do with modern C++ is using "std::remove_if" and lambda expression;

This code will remove "3" of the vector

vector<int> vec {1,2,3,4,5,6};
    
vec.erase(std::remove_if(begin(vec),end(vec),[](int elem){return (elem == 3);}), end(vec));

Solution 6 - C++

Do not erase and then increment the iterator. No need to increment, if your vector has an odd (or even, I don't know) number of elements you will miss the end of the vector.

Solution 7 - C++

You increment it past the end of the (empty) container in the for loop's loop expression.

Solution 8 - C++

The following also seems to work :

for (vector<int>::iterator it = res.begin(); it != res.end(); it++)
{
  res.erase(it--);
}

Not sure if there's any flaw in this ?

Solution 9 - C++

if(allPlayers.empty() == false) {
    for(int i = allPlayers.size() - 1; i >= 0; i--)
    {
        if(allPlayers.at(i).getpMoney() <= 0) 
            allPlayers.erase(allPlayers.at(i));
    }
}

This works for me. And Don't need to think about indexes have already erased.

Solution 10 - C++

As a modification to crazylammer's answer, I often use:

your_vector_type::iterator it;
for( it = res.start(); it != res.end();)
{
    your_vector_type::iterator curr = it++;
    if (something)
        res.erase(curr);
}

The advantage of this is that you don't have to worry about forgetting to increment your iterator, making it less bug prone when you have complex logic. Inside the loop, curr will never be equal to res.end(), and it will be at the next element regardless of if you erase it from your vector.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhidayatView Question on Stackoverflow
Solution 1 - C++PieterView Answer on Stackoverflow
Solution 2 - C++crazylammerView Answer on Stackoverflow
Solution 3 - C++JayhelloView Answer on Stackoverflow
Solution 4 - C++Patrice BernassolaView Answer on Stackoverflow
Solution 5 - C++Niki DimitrovView Answer on Stackoverflow
Solution 6 - C++BenoitView Answer on Stackoverflow
Solution 7 - C++kbjorkluView Answer on Stackoverflow
Solution 8 - C++Skippy le Grand GourouView Answer on Stackoverflow
Solution 9 - C++Dawoon YiView Answer on Stackoverflow
Solution 10 - C++Joseph PetroskeView Answer on Stackoverflow