РЕДАКТИРОВАТЬ: У меня было много ответов, в которых говорилось, что я должен разделить удаление в другой цикл . Возможно, я недостаточно прояснил это, но в последнем абзаце я заявил, что хотел бы найти иное решение. то есть сохраняя текущую структуру кода, но используя малоизвестную фу C ++ для ее работы.
Я знаю, что вызов erase ()
для вектора делает недействительными итераторы для элемента и все следующие за ним, и что erase ()
возвращает итератор к следующему действующему итератору, но что, если стирание произойдет где-то еще?
У меня следующая ситуация (упрощенная):
ПРЕДУПРЕЖДЕНИЕ. НЕ предполагайте, что это весь код. То, что показано ниже, ЧРЕЗВЫЧАЙНО упрощено для иллюстрации моей проблемы. Все классы и методы, показанные ниже, на самом деле намного сложнее.
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();
}
Таким образом, очевидно, что он выйдет из строя после запуска (* it) -> update ()
if x ()
возвращает истину, потому что, когда это произойдет, Ребенок скажет Родителю удалить его из вектора, аннулируя итератор.
Есть ли какой-либо способ исправить это, кроме как заставить Parent :: erase ()
передать итератор вплоть до Parent :: update ()
? Это было бы проблематично, так как она вызывается не для каждого вызова Child :: update ()
, и, таким образом, этой функции потребуется способ возвращать себе итератор каждый раз, а также в настоящее время возвращает другое значение. Я также предпочел бы избежать другого подобного способа отделения процесса стирания от цикла обновления.