Гарантируют ли итераторы STL действительность после изменения коллекции?

Допустим, у меня есть какая-то коллекция, и я получил итератор для ее начала. Теперь предположим, что я изменил коллекцию. Могу ли я по-прежнему безопасно использовать итератор, независимо от типа коллекции или итератора?

Чтобы избежать путаницы, вот порядок операций, о которых я говорю:

  1. Получите итератор коллекции.
  2. Измените коллекцию (очевидно, не элемент в ней, а саму коллекцию).
  3. Используйте итератор, полученный на шаге 1. Он все еще действителен в соответствии со стандартом STL?!

person user88637    schedule 25.07.2010    source источник
comment
Спасибо всем за быстрые ответы.   -  person user88637    schedule 25.07.2010


Ответы (3)


Зависит от контейнера. например если это vector, после изменения контейнера все итераторы могут стать недействительными. Однако, если это list, итераторы, не относящиеся к измененному месту, останутся действительными.

  • Итераторы вектора становятся недействительными при перераспределении его памяти. Кроме того, вставка или удаление элемента в середине вектора делает недействительными все итераторы, указывающие на элементы, следующие за точкой вставки или удаления. Из этого следует, что вы можете предотвратить аннулирование итераторов вектора, если вы используете reserve() для предварительного выделения столько памяти, сколько вектор когда-либо будет использовать, и если все вставки и удаления находятся в конце вектора. [1]

  • Семантика аннулирования итератора для deque следующая. Insert (включая push_front и push_back) делает недействительными все итераторы, ссылающиеся на deque. Erase в середине deque делает недействительными все итераторы, которые ссылаются на deque. Erase в начале или конце deque (включая pop_front и pop_back) делает итератор недействительным, только если он указывает на стертый элемент. [2]

  • List имеют важное свойство, состоящее в том, что вставка и объединение не делают недействительными итераторы для элементов списка, и что даже удаление делает недействительными только те итераторы, которые указывают на удаляемые элементы. [3]

  • Map имеет важное свойство: вставка нового элемента в map не делает недействительными итераторы, указывающие на существующие элементы. Стирание элемента с карты также не делает недействительными какие-либо итераторы, за исключением, конечно, тех итераторов, которые фактически указывают на стираемый элемент. [4] (то же самое для set, multiset и multimap)

person kennytm    schedule 25.07.2010
comment
Однако vector::insert(один элемент) и vector::erase возвращают новый допустимый итератор. - person Viktor Sehr; 25.07.2010
comment
Кенни: То, что вы говорите, соответствует стандарту или верно потому, что так обычно реализуется stl? Можете ли вы изменить свой ответ, чтобы он также объяснил это? благодаря. - person user88637; 25.07.2010
comment
@ yossi1981: это определено стандартом. Условия, при которых итераторы становятся недействительными, четко определены в стандарте. - person Martin York; 25.07.2010

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

person Jerry Coffin    schedule 25.07.2010
comment
что, если вы удалите элемент списка? Что, если это элемент, на который указывает итератор? - person m1tk4; 25.07.2010
comment
Стирание элемента, на который ссылается итератор, делает этот итератор недействительным. Стирание любого другого элемента (элементов) не выполняется. - person Jerry Coffin; 25.07.2010
comment
Другими словами, если вы измените список, есть обстоятельства, при которых он сделает итератор недействительным (указав на стертый элемент), поэтому действительность итератора не гарантируется - верно? - person m1tk4; 25.07.2010

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

person m1tk4    schedule 25.07.2010
comment
Строго говоря, это неверно (пример списка не соответствует этим правилам). - person Martin York; 25.07.2010
comment
Вопрос задавался вне зависимости от типа коллекции (контейнера). - person m1tk4; 25.07.2010
comment
Независимо от вопроса, утверждение, сделанное в вашем ответе, вводит в заблуждение, потому что оно верно в некоторых случаях и ложно во многих других. - person user487158; 04.11.2017