Reputation: 550
So I have a vector of unsigned ints (vector<unsigned int>
is called vector1
). I have another vector of a struct I created (vector<struct>
is called vector2
). vector<int>
holds an integer that is the index of the vector<struct>
. For example, let's say that vector<int = {5, 17, 18, 19}
. That means vector2.at(5) == vector2.at(vector1.at(0))
.
In the struct, I have a bool variable called var
. In most cases, var
is false. I want to delete all of the elements in vector1
that have var
= true.
What I did was:
for (unsigned int i = 0; i < vector1.size(); i++)
{
if (vector2.at(vector1.at(i)).var)
vector1.erase(vector.begin() + i);
}
The only problem with this is that it does not delete all of the true elements. I have run the for loop multiple times for all values to be delete. Is this the correct behavior? If it is not, where did I go wrong?
Upvotes: 0
Views: 377
Reputation: 45948
You are erasing elements in the vector while at the same time iterating over it. So when erasing an element, you always jump over the next element, since you increase i
while having just shortened the vector at i
(it would be even worse, had you used a proper iterator loop instead of an index loop). The best way to do this would be to seperate both opretions, first "marking" (or rather reordering) the elements for removal and then erasing them from the vector.
This is in practice best done using the erase-remove idiom (vector.erarse(std::remove(...), vector.end())
), which first uses std::remove(_if)
to reorganize the data with the non-removed elements at the beginning and returns the new end of the range, which can then be used to really delete those removed elements from the range (effectively just shortening the whole vector), using std::vector::erase
. Using a C++11 lambda, the removal condition can be expressed quite easily:
vector1.erase(std::remove_if( //erase range starting here
vector1.begin(), vector1.end(), //iterate over whole vector
[&vector2](unsigned int i) //call this for each element
{ return vector2.at(i).var; }), //return true to remove
vector1.end()); //erase up to old end
EDIT: And by the way, as always be sure if you really need std::vector::at
instead of just []
and keep in mind the implications of both (in particular the overhead of the former and "maybe insecurity" of the latter).
Upvotes: 1
Reputation: 5692
You can keep a temporary vector, copy of vector1
and iterate over it in the for
loop and delete from vector1
.
Upvotes: 1
Reputation: 63200
You have to use the erase-remove idiom to delete elements from a vector.
v.erase(std::remove(v.begin(), v.end(), value), v.begin);
std::remove
moves the elements to the end of the vector and erase
will erase the element from the vector.
Upvotes: 3