Что может вызвать «несовместимость итераторов» при сравнении итераторов из одного вектора? - PullRequest
2 голосов
/ 30 ноября 2011

Я работаю над пользовательским интерфейсом. Базовый класс для компонента пользовательского интерфейса UILayout, а весь пользовательский интерфейс представляет собой дерево объектов UILayout, а корень UILayout представляет весь экран. Чтобы содержать эту иерархию, любой заданный UILayout имеет вектор mChildren из boost::shared_ptr<UILayout>.

Объект UIManager заботится об обновлении всей иерархии UILayouts. Каждый вызов Update повторяет вектор mChildren, рекурсивно вызывая Update для каждого дочернего элемента.

Поскольку изменение формы вектора лишит законной силы эти итераторы, добавление и удаление записей из mChildren ограничивается методом ResizeChildren. Когда необходимо добавить или удалить компоненты, они добавляются в один из двух векторов, mChildrenPendingAddition и mChildrenPendingRemoval. Непосредственно перед циклом обновления вызывается ResizeChildren, и mChildren обновляется соответствующим образом. (Пожалуйста, остановите меня, если это единственный способ решения этой конкретной проблемы.)

Я получаю исключение, когда пытаюсь удалить из mChildren все записи, которые также содержатся в mChildrenPendingRemoval. Из UILayout :: ResizeChildren ():

mChildren.erase(remove_if(mChildren.begin(), mChildren.end(),
    IntersectsWithChildrenPendingRemoval(this)), mChildren.end());

Функция сравнения IntersectsWithChildrenPendingRemoval вызывает this-> ChildrenPendingRemovalContains (HUILayout ly), который выполняет следующие действия:

return (find(mChildrenPendingRemoval.begin(), mChildrenPendingRemoval.end(),
    ly) != mChildrenPendingRemoval.end());

Эта строка иногда не проходит утверждение отладки несовместимые векторные итераторы . Существует множество существующих вопросов по этой ошибке, но, похоже, она обычно указывает на то, что сравниваются два итератора из разных контейнеров. Но здесь это явно не так, верно? Что еще может вызвать эту проблему?

Соответствующий исходный код:

Это плагин, который я разрабатываю для многопоточного приложения. Тот факт, что проблема возникает с очень редкими и случайными интервалами, заставляет меня поверить, что это как-то связано с тем, что плагин работает в отдельных потоках, но все эти методы вызываются из одной функции, прямо в одной нить, а mChildren не доступен и не изменен ни в каком другом потоке.

Ответы [ 2 ]

0 голосов
/ 30 ноября 2011

Пожалуйста, остановите меня, если это единоличный способ решения этой конкретной проблемы

Почему бы вам не поработать с копией коллекции и сразу заменить ее:

std::list<X> copy(mChildren);

copy.insert(...);
copy.remove(...);
copy.insert(...);

// at once:
std::swap(copy, mChildren);

Дальнейшие мысли:

  • В общем случае не очень удобно хранить итераторы в изменяемых контейнерах в течение любого периода времени

  • Так как это контейнер умных указателей ... почему бы вам не передать сами умные указатели вокруг , если вам нужно сохранить «указатели» на элементы?(Конечно, это не включило бы итерацию, но в любом случае это не очень здоровое желание для ИМО)

0 голосов
/ 30 ноября 2011

Просто используйте индексы вместо итераторов.Итераторы переоценены.Они не более чем общие указатели.Наилучшим способом управления элементами в векторе всегда было и остается использование индексов.Если вы хотите использовать итераторы, попробуйте std :: list, в этом случае итераторы не будут аннулированы, даже если вы добавите элементы в список или удалите их.

...