РЕДАКТИРОВАТЬ: у меня было много ответов, говорящих мне, что я должен разделить удаление в другой цикл.Возможно, я не дал достаточно ясного объяснения, но в своем последнем абзаце я заявил, что хотел бы найти решение ДРУГОЕ, чем это.то есть, сохраняя текущую структуру кода, но используя какой-то малоизвестный фрейм 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()
, если x()
вернет true, потому что когда это произойдет, Child будетпопросите Родителя удалить его из вектора, сделав недействительным итератор.
Есть ли способ исправить это, кроме как заставить Parent::erase()
передать итератор полностью до Parent::update()
?Это было бы проблематично, так как не вызывается для каждого вызова Child::update()
, и, таким образом, этой функции потребуется способ возвращать итератор самому себе каждый раз, и она также в настоящее время возвращает другое значение.Я также предпочел бы избежать какого-либо другого аналогичного способа отделения процесса от цикла обновления.