Removing item from vector while iterating?
Solution 1
The most readable way I've done this in the past is to use std::vector::erase
combined with std::remove_if
. In the example below, I use this combination to remove any number less than 10 from a vector.
(For non-c++0x, you can just replace the lambda below with your own predicate:)
// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));
// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(),
[](int i) { return i < 10; }), v.end());
Solution 2
I agree with wilx's answer. Here is an implementation:
// curFiles is: vector < string > curFiles;
vector< string >::iterator it = curFiles.begin();
while(it != curFiles.end()) {
if(aConditionIsMet) {
it = curFiles.erase(it);
}
else ++it;
}
Solution 3
You can do that but you will have to reshuffle your while()
a bit, I think. The erase()
function returns an iterator to the element next after the erased one: iterator erase(iterator position);
. Quoting from the standard from 23.1.1/7:
The iterator returned from a.erase(q) points to the element immediately following q prior to the element being erased. If no such element exists, a.end() is returned.
Though maybe you should be using the Erase-remove idiom instead.
Solution 4
erase
returns a pointer to the next iterator value (same as Vassilis):
vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{ if(condition)
mit = myVec.erase(mit);
else
mit++;
}
Solution 5
If someone need working on indexes
vector<int> vector;
for(int i=0;i<10;++i)vector.push_back(i);
int size = vector.size();
for (int i = 0; i < size; ++i)
{
assert(i > -1 && i < (int)vector.size());
if(vector[i] % 3 == 0)
{
printf("Removing %d, %d\n",vector[i],i);
vector.erase(vector.begin() + i);
}
if (size != (int)vector.size())
{
--i;
size = vector.size();
printf("Go back %d\n",size);
}
}

Lucas
Updated on April 05, 2020Comments
-
Lucas about 3 years
I have a vector that holds items that are either active or inactive. I want the size of this vector to stay small for performance issues, so I want items that have been marked inactive to be erased from the vector. I tried doing this while iterating but I am getting the error "vector iterators incompatible".
vector<Orb>::iterator i = orbsList.begin(); while(i != orbsList.end()) { bool isActive = (*i).active; if(!isActive) { orbsList.erase(i++); } else { // do something with *i ++i; } }
-
harper over 12 yearsUsing the return value of erase you get a valid iterator back. So it's only necessary to assign the returned value to the iterator -- no performance issue here.
-
Kiran Kumar over 12 yearsAlso, to downsize the vector(as it seems to what the OP wants to do) the swap trick can be used. Details here:stackoverflow.com/questions/253157/how-to-downsize-stdvector
-
Oliver Charlesworth over 12 years@harper: Actually, there's a big performance issue here; erasing an item from the middle of a vector requires all the rest of them to be moved down, which involves O(N) constructor and destructor calls each time.
-
harper over 12 yearsAnd the use of an index has what befinit? How is the erasing performance increased? I just annotated the statement "iterators get invalidated .. no matter which form"...
-
jakebman over 12 yearsIt might be enough to say
i=orbsList.erase(i)
instead oforbsList.erase(i++)
-
EFreak over 10 yearsI know its a little late but you might wanna read this. Its contrary to what most people would expect but it comes from the creator of C++ bulldozer00.com/2012/02/09/vectors-and-lists
-
Josh Sanders almost 8 yearsWhile elegant in the simple case, I'm dubious of its effectiveness in the real world. This wouldn't even work at all with a dynamic size vector.
-
user1122069 about 6 yearsWhy not just size-- i-- next to erase?
-
jhasse almost 6 years"This wouldn't even work at all with a dynamic size vector." Why not?
-
Gelldur over 5 years@user1122069 my good practices forbids such things, a lot of people do not understand difference between
--i
nadi--
-
truthadjustr about 3 yearsWhile the
std::remove_if
lambda looks nice, but if I only want to delete exactly one element that matches the condition, it still goes through each element to the end. Therefore, I prefer manual iteration so I can break from the loop any time. -
Eric Reed about 2 yearsaccess the value at the iterator position using
*mit