Обнаружение и исправление неверного итератора

У меня есть странная проблема, которая редко случается с недействительными итераторами STL, которые я упростил в приведенном ниже примере кода.

foo.h

#include "Bar.h"#include <map>

class Foo
{
std::map<int, Bar*> test;
public:
Foo() {}
void Update();
void AddEntry(int i, Bar* bar);
void DeleteEntry(int i);
};

foo.cpp

#include "Foo.h"
void Foo::Update() {
for(auto iter = test.rbegin(); iter != test.rend(); iter++) {
iter->second->DoThingOne();
iter->second->DoThingTwo(); // BREAKS ON 2nd ITERATION
}
}

void Foo::AddEntry(int i, Bar* b) {
test[i] = b;
}

void Foo::DeleteEntry(int i) {
delete test[i];
test.erase(i);
}

bar.h

class Foo;
class Bar
{
Foo* f;
static int count;
public:
friend class Foo;
Bar(Foo* f_);
void DoThingOne();
void DoThingTwo();
};

Bar.cpp

#include "Bar.h"#include "Foo.h"
int Bar::count = 0;
Bar::Bar(Foo* f_) : f(f_) {}

void Bar::DoThingOne() {
if(count++ == 1) {
f->DeleteEntry(3);
}
}

void Bar::DoThingTwo() {
// Does things
}

main.cpp

#include "Foo.h"
int main() {
Foo* foo = new Foo();
Bar* one = new Bar(foo);
Bar* two = new Bar(foo);
Bar* three = new Bar(foo);

foo->AddEntry(1, one);
foo->AddEntry(2, two);
foo->AddEntry(3, three);

foo->Update();
return 0;
}

Так что в основном, когда Foo::Update 1-я итерация цикла выполняется нормально, затем 2-я итерация вызывает DoThingOne, который удаляет запись в карте, которую только что использовала предыдущая итерация цикла. когда DoThingTwo вызывается сразу после того, как я получаю сообщение об ошибке «Отладочное утверждение не удалось!

Из того, что я понимаю, итераторы над картами и наборами всегда действительны, за исключением итераторов, ссылающихся на удаленные элементы, но здесь итератор ссылается на элемент сразу после удаляемого элемента. Я могу только предположить, что это связано с тем, что удаляемый элемент является первым / последним элементом, а используемый итератор ссылается на новый первый / последний элемент, но я до сих пор не могу точно выяснить, почему это происходит. или как обойти это. У меня действительно есть возможность обнаружить, когда это происходит в цикле for перед вызовом DoThingTwo, и попытаться исправить это там.

Редактировать: просмотрев ссылку, предоставленную Nemo, я изменил цикл следующим образом, и он, кажется, работает:

void Foo::Update {
auto iter = test.end();
for(iter--; iter != test.begin(); iter--) {
iter->second->DoThingOne();
iter->second->DoThingTwo();
}
iter->second->DoThingOne();
iter->second->DoThingTwo();
}

Это выглядит очень неряшливо, но это делает работу. Поскольку использование итератора вместо reverse_iterator работает, я предполагаю, что оно как-то связано с тем, как работает reverse_iterator по сравнению с итератором.

2

Решение

Задача ещё не решена.

Другие решения


По вопросам рекламы [email protected]