EDIT: I have had a lot of answers telling me that I should separate the deletion into another loop. Perhaps I did not make it clear enough, but I stated in my last paragraph that I'd like to find a solution OTHER than that. ie keeping the current code structure, but using some little-known C++fu to make it work.
Well, I know that calling erase()
on a vector invalidates iterators to the element and all those after it, and that erase()
returns an iterator to the next valid iterator, but what if the erase happens elsewhere?
I have the following situation (simplified):
WARNING: Do NOT assume that this is the entire code. What is shown below is EXTREMELY simplified to illustrate my problem. All the classes and methods shown below are actually far more complex.
class Child {
Parent *parent;
}
class Parent {
vector<Child*> child;
}
void Parent::erase(Child* a) {
// find an iterator, it, that points to Child* a
child.erase(it);
}
int Child::update() {
if(x()) parent.erase(*this) // Sometimes it will; sometimes (most) it won't
return y;
}
void Parent::update() {
int i = 0;
for(vector<A>::iterator it = child.begin(); it != child.end(); it++)
i += (*it)->update();
}
So, obviously, it will crash after it runs (*it)->update()
if x()
returns true, because when it does, the Child will tell the Parent to remove it from the vector, invalidating the iterator.
Is there any way of fixing this other than making Parent::erase()
pass an iterator all the way back up to Parent::update()
? This would be problematic, as it is not called for every call to Child::update()
, and thus that function would need a way to return an iterator to itself every single other time, and it is also currently returning another value. I would also prefer to avoid some other similar way to separate the erasing the process from the updating loop.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…