Правила аннулирования 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();
гарантированно работает нормально, независимо от того, перераспределяет вектор или нет.