2013-06-03 6 views
28

Я вижу, что он много ссылался, но не дал четкого ответа на вопрос, что именно. Мой опыт связан с языками более высокого уровня, поэтому я не знаком с наличием недействительности в рамках коллекций.Что такое недействительность итератора?

Что такое антагонизм итератора?

Почему это происходит? С чем это трудно?

+2

Также это [Правила аннулирования итератора] (http://stackoverflow.com/questions/6438086/iterator-invalidation-rules) – mwerschy

+0

Возможно, мне понадобится немного лучшего объяснения этого, я не думал, что это имело какое-либо отношение к языкам высокого/низкого уровня. Я знаю, что вы не можете изменить список во время итерации в 'C#'. –

+4

Голосование за открытие ... «что есть» - это другой вопрос, на который не ответили в связанной теме. – djechlin

ответ

34
  1. Итераторы - прославленные указатели. Недействительность Iterator очень похожа на недействительность указателя; это означает, что он внезапно указывает на нежелательные данные.

  2. Потому что это очень естественно, но не так, чтобы сделать что-то вроде этого:

    for(iterator it = map.begin(); it != map.end(); ++it) { 
        map.erase(it->first); 
        // whoops, now map has been restructured and iterator 
        // still thinks itself is healthy 
    } 
    
  3. Потому что ошибка прямо там? Ошибка компилятора, никаких предупреждений, вы теряете. Вам просто нужно хорошо подготовиться, чтобы следить за ними и предотвращать их. Очень коварные ошибки, если вы не знаете, что делаете. Одной из концепций дизайна C++ является скорость над безопасностью. Проверка времени выполнения, которая приведет к недействительности итератора к исключению вместо неуказанного поведения, слишком дорога, с точки зрения разработчиков языка C++.

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

+8

Вот почему мне нравится то, что Visual Studio имеет отладочные сборки. По умолчанию стандартные контейнеры C++ проверяют, действительны ли они в сборках отладки, помогая найти эти коварные ошибки. –

+0

@MooingDuck, вы не должны полагаться на это поведение. Если вы слишком привязаны к удивительным функциям компилятора, когда вы переходите на другую платформу (что может произойти некоторое время в будущем), вы получите ожог, жесткий и быстрый. –

+5

@ RichardJ.RossIII: В зависимости от? Совершенно очевидно. Но приятно иметь дополнительный слой защиты, когда я придираюсь. –

6

итератора недействительности это то, что происходит, когда тип итератора (объект поддержки операторов ++ и *) не правильно отражают состояние объекта, итерация. Например:

int *my_array = new int[15]; 
int *my_iterator = &my_array[2]; 

delete[] my_array; 

std::for_each(my_iterator, my_iterator + 5, ...); // invalid 

Это приводит к неопределенному поведению, поскольку память, на которую он указывает, была восстановлена ​​ОС.

Это только один сценарий, и многие другие причины делают итератор «недействительным», и вы должны быть осторожны, чтобы проверить документацию об объектах, которые вы используете.

4

Проблема возникает, когда контейнер, который обрабатывается с использованием итератора, имеет форму, измененную во время процесса. (Мы будем использовать однопоточное приложение, одновременный доступ к изменяемому контейнеру - это целая «черная червь червей», на которую мы не войдем на этой странице). Под термином «имеет свое изменение формы», один из следующих типов мутаций означали:

  • вставка в контейнер (в любом месте)
  • Удаления из элемента из контейнера
  • Любых операций который изменяет ключ (вАссоциативныйконтейнер)
  • Любая операция, которая изменяет порядок элементов в сортированном контейнере.
  • Более сложная операция , состоящая из одного или нескольких из указанных выше (например, разбиение контейнера на два).

(От: http://c2.com/cgi/wiki?IteratorInvalidationProblem)

Концепция на самом деле довольно простой, но побочные эффекты могут быть весьма раздражает. Я бы добавил, что эта проблема влияет не только на C/C++, но и на другие языки низкого или среднего уровня. (В некоторых случаях, даже если они не позволяют прямое распределение кучи)

+0

Ключи не могут быть изменены в любом ассоциативном контейнере, о котором я знаю. –

+0

@MooingDuck это действительно зависит от того, что вы считаете «ключевым изменением». Я мог бы удалить значение для одного ключа и добавить это значение для другого ключа, разве это не «изменение ключа»? Просто потому, что контейнеры не поддерживают что-то, не означает, что это невозможно. –

+0

@ RichardJ.RossIII: Я считаю, что сообщение/ссылка ссылаются на фактическую модификацию самой _key _, а не на значение, связанное с указанным ключом. В большинстве случаев для изменения связанных данных требуется аннулирование итератора. Модификация самой _key_ потребует (теоретического) стирания/повторного ввода. –

Смежные вопросы