Что является безопасным эквивалентом незаполненного стирания STL? - PullRequest
4 голосов
/ 20 октября 2008

Предположим, у меня есть hash_map и код вроде

// i is an iterator
i = hash_map.erase(i)

Но STL GCC не возвращает итератор при удалении, а пустоту. Теперь код как

hash_map.erase(i++)

безопасно (то есть не делает недействительным итератор или делает какие-либо другие неожиданные или неприятные вещи)? Обратите внимание, что это hash_map.

Ответы [ 3 ]

6 голосов
/ 20 октября 2008

Да, это безопасно, потому что значение i будет установлено на следующее значение, прежде чем текущее значение будет стерто.

Согласно документации SGI о хэшированных контейнерах аннулирование не происходит ни для не стертых элементов, ни даже для изменения размера (нет слов о том, вызывают ли вставки изменение размера, поэтому, чтобы быть осторожным, я признаю, что как возможность) --- но в последнем случае порядок итераций будет изменен. Но это не применимо здесь, если вы не сделаете все возможное, чтобы изменить размер контейнера во время обхода или чего-то еще. : -)

2 голосов
/ 21 февраля 2010

Вы можете инкапсулировать удаление, чтобы обеспечить одинаковый интерфейс для всех используемых вами контейнеров:

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);
}

Для этого требуется:

  1. c.erase возвращает итератор для следующего элемента. Так работает вектор, дек и список.
  2. c.erase возвращает void и не делает недействительным следующий итератор. Вот как работают map, set и (не stdlib) hash_map.
0 голосов
/ 21 октября 2008

Ненавижу дождь на параде, но я не думаю, что то, что вы предлагаете, безопасно.

i ++ - это оператор постинкремента, что означает, что i увеличивается после вызова стирания. Но стирание делает недействительными все итераторы, указывающие на удаляемый элемент. Так что к тому времени, когда я увеличивается, это уже не действует.

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

Насколько я знаю, нет никакого способа обойти это, но что-то вроде:

// tmp and i are both iterators
tmp = i;
++i;
hash_map.erase(tmp);
...