Правила аннулирования insert_iterator

Какие действия с контейнером STL могут сделать C++ недействительным std::insert_iterator ссылаясь на этот контейнер? Является insert_iterator действителен, если его основной итератор (защищенный член iter), подчиняется ли обычным правилам аннулирования Iterator?

Связанный: std:: insert_iterator и аннулирование итератора приводит пример недопустимого insert_iterator но не выяснил правила.

2 ответа

Решение

Действителен ли insert_iterator, если его основной итератор (защищенный член iter)

Вы правы, вот почему защищенный элемент указан в спецификации и функции, которые работают на insert_iterator (В частности, operator=, так как остальное не-операции) определяются в терминах функций, которые iter

Ну, ответ зависит от того, о чем конкретно вы спрашиваете.

(Чтобы избавиться от этого, я хотел бы сразу отметить, что ваша ссылка "Связанные" совершенно не связана. Проблема с кодом по этой ссылке не имеет абсолютно никакого отношения к insert_iterator недействительности. Автор этого вопроса неверно истолковал проблему и в итоге попытался решить несуществующую проблему, в то время как реальная проблема сохранялась. Я также дал дополнительный ответ на этот вопрос.)

Если вы создаете insert_iterator ins от действительного итератора container::iterator it а затем самостоятельно сделать что-то с контейнером, который сделает недействительным it, затем ins также будет признан недействительным. Это то, что естественно ожидать. ins не может знать, что что-то случилось с контейнером, если вы делаете это самостоятельно.

Однако в то же время insert_iterator имеет самовосстанавливающиеся свойства при использовании для введения. Например, если вы используете insert_iterator ins вставить данные в vector, ins остается действительным, даже если вектор проходит перераспределение. Т.е. даже если перераспределение вектора является массовым событием, лишающим законной силы итератора, оно не наносит ущерба ins (при условии, конечно, что перераспределение было вызвано вставкой, выполненной через ins).

Это следует из стандартного алгоритма вставки

it = container->insert(it, value);
++it;

где it является лежащим внутри итератором точки вставки insert_iterator, Итераторы с фронтальной и обратной вставкой также имеют одинаковые свойства самовосстановления. Потенциально недопустимый внутренний итератор немедленно повторно проверяется.

Чтобы проиллюстрировать разницу, рассмотрим этот простой пример

std::vector<int> v(10);
std::vector<int>::iterator it = v.begin() + 5;

for (unsigned n = 20; n > 0; --n)
  v.insert(it, rand());

Этот код, как правило, недопустим, поскольку весьма вероятно, что контейнер будет перераспределен во время цикла вставки, что приведет к аннулированию it и делает все последующие вставки недействительными.

В то же время этот код

std::vector<int> v(10);
std::vector<int>::iterator it = v.begin() + 5;
std::insert_iterator<std::vector<int> > it_ins(v, it);

for (unsigned n = 20; n > 0; --n)
  *it_ins++ = rand();

гарантированно работает нормально, независимо от того, перераспределяет вектор или нет.

Другие вопросы по тегам