! | Данная информация предназначена только только для IT-специалистов по системной интеграции модулей БИОСОФТ-М. (см. Руководства пользователя к программным продуктам) |
Нельзя продолжать iter-ирование map<> после удаления из него элементов.
Нельзя использовать iter от одного map для итерации другого.
Теперь для ПРД приложений делается автоматическая верификация этих правил во избежании фатальной коррупции памяти. При нарушении правил выдается ассерт. Игнорировать его нельзя, последствия этого будут неопределены (хотя и не фатальны в релизе).
В iter хранится POS которая по сути голый указатель на следующую пару key-->value в map.
Если эту пару удалить (RemoveAtKey, RemoveAll) то на следующем круге цикла пойдет коррупция.
С итератором и текущим состоянием map-контейнера ассоциированы уникальные сигнаруры.
Сигнатура заносится в iter при первом вызове Iterate (IterateKeys).Сигнатура в map обнрвляется при удалении элементов.На последующих кругах итерации сверяются сигнатуры iter и map. При несовпадении FAIL/return false
Сигнатуры глобально уникальны между всеми модулями процесса в рамках которых они получаются инкрементом в специальной разделяемой памяти.
Где array и Find() достаточны.
Проблемы вообще нет если к map только добавляются элементы. Тогда можно публиковать Iterate по ней. Если же удаление необходимо то Iterate может работать по array который автоматически синхронизируется с map (map используется как индекс в array). Однако все равно при удалении из массива будут вопросы о том что станет с индексом в итераторе, но это уже офтоп.
Для локальных циклов где удаление не разнесено далеко от итератора можно рестартовать обработку элементов
for_i(iRepeat, nCount) { bool bRestart = false; for (map.Iterate()) { ... map.Remove... bRestart = true; break; } if (!bRestart) { break; } }
Копию делать либо в array (эффективней) или в другой map. И итерировать копию. спокойно удаляя из основного map.
Один из вариантов решения для глубоко инкапсулированных Iterate() интерфейсов - сохранить копию map, или array ключей в Qmap хранит расширенный контекст итератора по которой итерировать независимо от меняющегося исходного map.
Соствлять список того, что надо удалить или ставить элементам флаг "удалено". Применять физическое удаление к map в отложенном режиме если этого допускает логика (по таймеру и т.п.). Будет работать если клиент не хранит iter а использует только локально (что всегда настоятельно рекомендуется во избежении кашмарных проблем всюду).
Давно думаю о таком хотя бы как опциональной альтернативе. Он будет заведомо более медленным чем не толерантный к удалению.
Возможный вариант реализации: хранение в iter копии уже проитерированных ключей которые используются для автоматического Iterate-recovery and resume when deletion during iteration is detected.
Другие решения, в частности временная блокировка следующего итерируемого элемента (собственно источника всей проблемы) от удаления слишком усложняют и замедляют всю работу map<>.
нигде эффективного встроенного решения не вижу: