C++: использование итератора density_hash_set после стирания (*it)
У меня есть этот файл кода C++, который находится под лицензией Expat. При запуске cppcheck в коде я получаю эту ошибку:
[google_hash.cpp:137] -> [google_hash.cpp:141]: (error) Iterator 'it' used after element has been erased.
Код в вопросе:
74 #if (FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__SPARSE)
75 typedef sparse_hash_set<char *, state_hash, state_equality> StatesGoogleHash;
76 #else
77 typedef dense_hash_set<char *, state_hash, state_equality> StatesGoogleHash;
78 #endif
.
.
.
131 extern void fc_solve_states_google_hash_foreach(
132 fcs_states_google_hash_handle void_hash,
133 bool (*should_delete_ptr)(void *key, void *context), void *context)
134 {
135 StatesGoogleHash *hash = (StatesGoogleHash *)void_hash;
136
137 for (StatesGoogleHash::iterator it = hash->begin(); it != hash->end(); ++it)
138 {
139 if (should_delete_ptr(*(it), context))
140 {
141 hash->erase(it);
142 }
143 }
144 }
Он использует http://goog-sparsehash.sourceforge.net/doc/sparse_hash_set.html или http://goog-sparsehash.sourceforge.net/doc/dense_hash_set.html.
Теперь эти документы говорят, что
Validity of Iterators
insert() invalidates all iterators, as does resize().
erase() is guaranteed not to invalidate any iterators.
Таким образом, мой вопрос - правильно ли я использую итераторы наборов правильно и безопасно (а cppcheck выдал ложное срабатывание), или если нет - как должен быть исправлен код?
Помощь будет оценена.
1 ответ
Это ложный позитив в том смысле, что cppcheck считает, что API называется erase
на iterator
делает недействительным итератор. Это правило, которое оно использует, потому что это разумный API.
Тогда для этого кода, кажется, допустимо сделать ++it
из-за этого:
Это реализовано, когда erase() не изменяет размер хеш-таблицы. Если вам нужна максимальная эффективность использования пространства, вы можете вызвать resize(0) после строки вызовов erase(), чтобы принудительно изменить размер хеш-таблицы до минимально возможного размера.
Похоже, это означает, что итераторы могут встретить удаленные объекты, если вы не вызываете resize(0)
между стиранием. Здесь все хорошо, потому что стирание выполняется в одном цикле.
Тот факт, что этот код скрывает свое поведение, не делая его очевидным и не использует стандартные шаблоны, не помогает.