EDIT: у меня было много ответов, в которых говорилось, что я должен отделить удаление в другом цикле. Возможно, я недостаточно четко прояснил ситуацию, но в своем последнем абзаце я заявил, что хочу найти решение, отличное от этого. т.е. сохраняя текущую структуру кода, но используя немного малоизвестный С++ fu, чтобы заставить его работать.
Ну, я знаю, что вызов 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, потому что когда это произойдет, Ребенок скажет родительу удалить его из вектора, недействительным итератором.
Есть ли способ исправить это иначе, чем сделать Parent::erase()
передать итератор полностью обратно на Parent::update()
? Это было бы проблематично, поскольку он не вызывался для каждого вызова Child::update()
, и, следовательно, для этой функции понадобился бы способ вернуть итератор к себе каждый раз в другое время, а также в настоящее время возвращает другое значение. Я также предпочел бы избежать другого аналогичного способа разделения стирания процесса из цикла обновления.