Что является безопасным эквивалентом незаполненного стирания STL?

StackOverflow https://stackoverflow.com/questions/217892

  •  03-07-2019
  •  | 
  •  

Вопрос

Предположим, у меня есть 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);
}

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

<Ол>
  • c.erase возвращает итератор для следующего элемента. Так работают вектор, дек и список.
  • c.erase возвращает void и не делает недействительным следующий итератор. Вот как работают map, set и (не stdlib) hash_map.
  • Ненавижу дождь на параде, но я не думаю, что то, что ты предлагаешь, безопасно.

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

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

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

    // tmp and i are both iterators
    tmp = i;
    ++i;
    hash_map.erase(tmp);
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top