Что является безопасным эквивалентом незаполненного стирания STL?
Вопрос
Предположим, у меня есть hash_map и код типа
// i is an iterator
i = hash_map.erase(i)
Но STL GCC не возвращает итератор при удалении, а пустоту. Теперь код похож на
hash_map.erase(i++)
безопасно (то есть не делает недействительным итератор или делает какие-либо другие неожиданные или неприятные вещи)? Обратите внимание, что это hash_map.
Решение
Да, это безопасно, потому что значение i
будет установлено на следующее значение, прежде чем текущее значение будет стерто.
Согласно документации SGI о хэшированных контейнерах аннулирование не происходит для не стертые элементы, даже для изменения размера (нет слов о том, вызывают ли вставки изменение размера, поэтому, чтобы быть осторожным, я допускаю это как возможность) --- но в последнем случае порядок итераций будет изменен. Но это не применимо здесь, если вы не сделаете все возможное, чтобы изменить размер контейнера во время обхода или чего-то еще. : -)
Другие советы
Вы можете инкапсулировать удаление, чтобы обеспечить одинаковый интерфейс для всех используемых вами контейнеров:
namespace detail {
template<typename Container, typename R>
struct SelectErase {
// by default, assume the next iterator is returned
template<typename Iterator>
Iterator erase(Container& c, Iterator where) {
return c.erase(where);
}
};
// specialize on return type void
template<typename Container>
struct SelectErase<Container, void> {
template<typename Iterator>
Iterator erase(Container& c, Iterator where) {
Iterator next (where);
++next;
c.erase(where);
return next;
}
};
template<typename I, typename Container, typename R>
SelectErase<Container,R> select_erase(R (Container::*)(I)) {
return SelectErase<Container,R>();
}
} // namespace detail
template<typename Container, typename Iterator>
Iterator erase(Container& container, Iterator where) {
return detail::select_erase<Iterator>(&Container::erase).erase(container, where);
}
Для этого требуется либо:
<Ол>Ненавижу дождь на параде, но я не думаю, что то, что ты предлагаешь, безопасно.
i ++ - это оператор постинкремента, что означает, что i увеличивается на единицу после вызова стирания. Но стирание делает недействительными все итераторы, указывающие на удаляемый элемент. Так что к тому времени, когда я увеличивается, это уже не действует.
Если вам повезет, он может работать случайно случайно, пока однажды он перестанет работать.
Насколько я знаю, нет никакого способа обойти это, но что-то вроде:
// tmp and i are both iterators
tmp = i;
++i;
hash_map.erase(tmp);