Vector erase & continue traversal
by Lateral Punk · in Torque Game Engine · 11/06/2006 (7:14 pm) · 9 replies
What's the proper way to erase from a Vector (or VectorPtr) AND continue traversing it (ie. to find more items to delete with the input value)? I know if you don't do this correctly, it causes problems. Is it something like this:
Notice the placements of continue & i++. Is this the right way to do it?
Vector<myobj>::iterator i;
for(i = list.begin();i != list.end();)
{
myobj *obj = *i;
if (obj == objtoerase)
{
list.erase(i);
continue;
}
i++;
}Notice the placements of continue & i++. Is this the right way to do it?
#2
11/06/2006 (8:15 pm)
Backwards..good idea. Do you know how to do it in torque?
#3
I was just about to get back to work on another project I've been working on, so I don't want to hunt through the Vector header file right now. However, I just realized that your code might end up skipping the last item (as would a simple 'reversal' of the code to go through it backwards), but maybe this (untested) code will go:
But this code is so ugly, there has to be a better way...
Finally, as I look at what this code is really doing, and again without looking at the Vector header file, isn't there a way to either:
A) remove an object directly by reference (ie., list.remove(objtoerase))?
or
B) look up the index of an object by reference, and then delete that index?
If you are only going to remove a single known object, and not all objects with a particular attribute, etc..., why bother iterating in the first place?
11/06/2006 (8:49 pm)
No, lol.I was just about to get back to work on another project I've been working on, so I don't want to hunt through the Vector header file right now. However, I just realized that your code might end up skipping the last item (as would a simple 'reversal' of the code to go through it backwards), but maybe this (untested) code will go:
Vector<myobj>::iterator i;
for(i = list.end();;)
{
myobj *obj = *i;
if (obj == objtoerase)
{
list.erase(i);
}
if(i == list.begin())
break;
i--;
}But this code is so ugly, there has to be a better way...
Finally, as I look at what this code is really doing, and again without looking at the Vector header file, isn't there a way to either:
A) remove an object directly by reference (ie., list.remove(objtoerase))?
or
B) look up the index of an object by reference, and then delete that index?
If you are only going to remove a single known object, and not all objects with a particular attribute, etc..., why bother iterating in the first place?
#4
11/06/2006 (8:53 pm)
I am not removing a single known object. There might be duplicates (like trying to remove all occurences of "7" in a list of integers). Your above code looks ok, but can't tell without testing it. There are methods to retreive by index, but i rather use the iterator. thanks for your input!
#5
11/09/2006 (9:35 am)
Here's an example using both direct reference vector[i] and iterators#include <iostream>
#include <vector>
using namespace std;
void main()
{
int i;
vector<int> V;
vector<int>::iterator vi;
// populate V with numbers 1...20
for(i=1; i<=20; i++) V.push_back(i);
// delete all multiples of 5 using direct reference
for(i=0; i<V.size(); i++)
{
if(V[i]%5==0)
{
V.erase(V.begin()+i);
i--;
}
}
// print
cout << "multiples of 5 removed: " << endl;
for(i=0; i<V.size(); i++) cout << V[i] << " ";
cout << endl;
// multiples of 3 removed using iterator
vi=V.begin();
while(vi!=V.end())
{
if((*vi)%3==0) V.erase(vi);
else vi++;
}
// print
cout << "multiples of 3 removed: " << endl;
for(i=0; i<V.size(); i++) cout << V[i] << " ";
cout << endl;
// so it pauses during debug
cin >> V[0];
}
#6
- find the index of the item to be deleted
- overwrite the data at that index with the data from the last item in the vector, vector.end()
- then delete vector.end()
C++ also has a List class, which is almost exactly like vector but its a linked list. Lists are MUCH slower on access though (stl vector have identical access speed to a normal C array). So only use Lists it if you sort, insert, and delete from your list very often.
11/09/2006 (9:50 am)
BTW, vectors are contiguous memory, so if you delete from the middle all the remaining items in the list must be moved forward. (Not sure exactly how they implement that in the STL code). So if you are deleting very often, for performance reasons you may want to:- find the index of the item to be deleted
- overwrite the data at that index with the data from the last item in the vector, vector.end()
- then delete vector.end()
C++ also has a List class, which is almost exactly like vector but its a linked list. Lists are MUCH slower on access though (stl vector have identical access speed to a normal C array). So only use Lists it if you sort, insert, and delete from your list very often.
#7
11/09/2006 (9:55 am)
Hmm this is even cleaner looking search/delete loop:for(vi=V.begin(); vi!=V.end(); )
{
if((*vi)%3==0) V.erase(vi);
else vi++;
}
#8
11/09/2006 (9:57 am)
So basic idea is if you're going forward, don't increment the iterator if you've just deleted something. I'm using the torque built-in Vector class which has nothing to do with STL per se. thanks!
#9
.. altho personally i'd throw a few more newlines and other whitespace in there ;)
11/09/2006 (10:38 am)
What David illustrated is how i've seen it done with STL... altho personally i'd throw a few more newlines and other whitespace in there ;)
Torque Owner Brian Hill
However, the way you've written it might work just fine, depending on how the ++ operator is implemented.