Итератор правила о признании недействительными



каковы правила недействительности итератора для контейнеров C++?



желательно в формате сводного списка.



(Примечание:это должно быть запись в C++ FAQ Stack Overflow. Если вы хотите критиковать идею предоставления FAQ в этой форме, то публикация на meta, которая начала все это было бы место, чтобы сделать это. Ответы на этот вопрос отслеживаются в в C++ чат, где идея FAQ началась в во-первых, поэтому ваш ответ, скорее всего, будет прочитан теми, кто придумал эту идею.)

753   4  

4 ответов:

C++03 (источник: Правила Аннулирования Итератора (C++03))


вставка

контейнеры последовательности

  • vector: все итераторы и ссылки до точки вставки не затрагиваются, если новый размер контейнера не превышает предыдущую емкость (в этом случае все итераторы и ссылки недействительны) [23.2.4.3/1]
  • deque: все итераторы и ссылки недействительны, если вставленный элемент не находится в конце (спереди или сзади) deque (в этом случае все итераторы недействительны, но ссылки на элементы не затрагиваются) [23.2.1.3 / 1]
  • list: все итераторы и ссылки не затрагиваются [23.2.2.3 / 1]

ассоциативные контейнеры

  • [multi]{set,map}: все итераторы и ссылки не затрагиваются [23.1.2 / 8]

контейнер адаптеры

  • stack: наследуется от базового контейнера
  • queue: наследуется от базового контейнера
  • priority_queue: наследуется от базового контейнера

уничтожение

контейнеры последовательности

  • vector: каждый итератор и ссылка после точки стирания недействительны [23.2.4.3 / 3]
  • deque: все итераторы и ссылки недействительны, если только удаленные члены не находятся в конце (спереди или сзади) deque (в этом случае недействительны только итераторы и ссылки на удаленные члены) [23.2.1.3 / 4]
  • list: недействительны только итераторы и ссылки на стертый элемент [23.2.2.3 / 3]

ассоциативные контейнеры

  • [multi]{set,map}: признаны недействительными только итераторы и ссылки на стертые элементы [23.1.2/8]

контейнер переходник

  • stack: наследуется от базового контейнера
  • queue: наследуется от базового контейнера
  • priority_queue: наследуется от базового контейнера

изменение размера

  • vector: согласно вставке / стиранию [23.2.4.2 / 6]
  • deque: согласно вставке / стиранию [23.2.1.2 / 1]
  • list: как за вставку / стирание [23.2.2.2 / 1]

Примечание 1

если не указано иное (либо явно или путем определения функции с точки зрения других функций), вызывая функция-член контейнера или передача контейнер в качестве аргумента a библиотечная функция не является недействительной итераторы to, или изменить значения, объекты внутри этого контейнера. [23.1/11]

Примечание. 2

в C++2003 неясно, подчиняются ли итераторы " end " вышеуказанным правилам; вы должны предположить, во всяком случае, что они есть (как это имеет место на практике).

Примечание 3

правила для недействительности указателей-это имена как правила для недействительности ссылок.

C++11 (источник: правила аннулирования итератора (C++0x))


вставка

контейнеры последовательности

  • vector: все итераторы и ссылки до точки вставки не затрагиваются, если новый размер контейнера не превышает предыдущую емкость (в этом случае все итераторы и ссылки недействительны) [23.3.6.5/1]
  • deque: все итераторы и ссылки недействительны, если вставленный элемент не находится в конце (спереди или сзади) deque (в этом случае все итераторы недействительны, но ссылки на элементы не затрагиваются) [23.3.3.4/1]
  • list: все итераторы и ссылки не затрагиваются [23.3.5.4 / 1]
  • forward_list: все итераторы и ссылки без изменений (относится к insert_after) [23.3.4.5/1]
  • array: (n/a)

ассоциативные контейнеры

  • [multi]{set,map}: все итераторы и ссылки не затрагиваются [23.2.4 / 9]

несортированные ассоциативные контейнеры

  • unordered_[multi]{set,map}: все итераторы недействительны при повторном хэшировании, но ссылки не затрагиваются [23.2.5 / 8]. Повторное хэширование не происходит, если вставка не приводит к превышению размера контейнера z * B где z это максимальный коэффициент нагрузки и B текущее количество ведер. [23.2.5/14]

контейнер переходник

  • stack: наследуется от базового контейнера
  • queue: наследуется от базового контейнера
  • priority_queue: наследуется от базового контейнера

уничтожение

последовательность контейнеры

  • vector: каждый итератор и ссылка в точке стирания или после нее недействительны [23.3.6.5 / 3]
  • deque: удаление последнего элемента делает недействительными только итераторы и ссылки на удаленные элементы и итератор прошлого конца; удаление первого элемента делает недействительными только итераторы и ссылки на удаленные элементы; удаление любых других элементов делает недействительными все итераторы и ссылки (включая итератор прошлого конца) [23.3.3.4/4]
  • list: недействительны только итераторы и ссылки на стертый элемент [23.3.5.4 / 3]
  • forward_list: недействительны только итераторы и ссылки на стертый элемент (относится к erase_after) [23.3.4.5/1]
  • array:(n/a)

ассоциативные контейнеры

  • [multi]{set,map}: только итераторы и ссылки на стертые элементы аннулирование [23.2.4/9]

неупорядоченные ассоциативные контейнеры

  • unordered_[multi]{set,map}: недействительны только итераторы и ссылки на стертые элементы [23.2.5 / 13]

контейнер переходник

  • stack: наследуется от базового контейнера
  • queue: наследуется от базового контейнера
  • priority_queue: унаследованный от базового контейнер

изменение размера

  • vector: согласно вставке / стиранию [23.3.6.5 / 12]
  • deque: согласно вставке / стиранию [23.3.3.3 / 3]
  • list: согласно вставке / стиранию [23.3.5.3 / 1]
  • forward_list: согласно вставке / стиранию [23.3.4.5 / 25]
  • array: (n / a)

Примечание 1

если не указано иное (либо явно или путем определения функции с точки зрения других функций), вызывая функция-член контейнера или передача контейнер в качестве аргумента a библиотечная функция не является недействительной итераторы to, или изменить значения, объекты внутри этого контейнера. [23.2.1/11]

примечание 2.

никакая функция swap() не делает недействительными любые ссылки, указатели или итераторы ссылаясь на элементы стеклотара меняясь местами. [ Примечание:в end () iterator не относится ни к одному элемент, так это могут быть признаны недействительными. -конец Примечание ] [23.2.1/10]

Примечание 3

кроме вышеуказанного предостережения относительно swap(),неясно, подчиняются ли итераторы " end " вышеперечисленным правилам для каждого контейнера; вы должны предположить, во всяком случае, что они есть.

примечание 4

vector и все неупорядоченные ассоциативные контейнеры поддержка reserve(n) что гарантирует, что автоматическое изменение размера не произойдет, по крайней мере, до тех пор, пока размер контейнера не вырастет до n. Осторожность следует принимать с неупорядоченные ассоциативные контейнеры потому что будущее предложение позволит определить минимальный коэффициент нагрузки, который позволит повторному хэшу произойти на insert после достаточно erase операции уменьшают размер контейнера ниже минимального; гарантия должна быть считается потенциально недействительным после erase.

вероятно, стоит добавить, что итератор вставки любого вида (std::back_insert_iterator,std::front_insert_iterator,std::insert_iterator) гарантированно остается действительным до тех пор, пока все вставки выполняются через этот итератор и не происходит никакого другого события, делающего итератор недействительным.

например, когда вы выполняете ряд операций вставки в std::vector С помощью std::insert_iterator вполне возможно, что вектор будет испытывать событие перераспределения, которое сделает недействительными все итераторы, которые "указывают" в этот вектор. Однако итератор вставки, о котором идет речь, гарантированно остается действительным, т. е. вы можете безопасно продолжить последовательность вставок. Там нет необходимости беспокоиться о запуске векторного перераспределения вообще.

это, опять же, относится только к вставкам, выполняемым через сам итератор вставки. Если событие iterator-invalidating инициируется каким-либо независимым действием на контейнере, то итератор insert также становится недействительным в соответствии с общим правила.

например, этот код

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();

гарантированно выполняет допустимую последовательность вставок в вектор, даже если вектор "решает" перераспределить где-то в середине этого процесса.

поскольку этот вопрос привлекает так много голосов и вроде бы становится FAQ, я думаю, было бы лучше написать отдельный ответ, чтобы упомянуть одно существенное различие между C++03 и C++11 в отношении влияния std::vectorоперация вставки по валидности итераторов и ссылок относительно reserve() и capacity(), который самый популярный ответ не заметил.

C++ 03:

перераспределение недействительными все ссылки, указатели и итераторы ссылаясь на элементы в последовательности. Гарантируется, что нет перераспределение происходит во время вставок, которые происходят после вызова зарезервируйте() до тех пор, пока вставка не сделает размер вектор превышает размер, указанный в последнем вызове резерв().

C++11:

перераспределение недействительными все ссылки, указатели и итераторы ссылаясь на элементы в последовательность. Гарантируется, что нет перераспределение происходит во время вставок, которые происходят после вызова зарезервируйте() до тех пор, пока вставка не сделает размер вектор больше, чем значение емкости().

так что в C++03 это не "unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated)" как уже упоминалось в другой ответ, вместо этого он должен быть "greater than the size specified in the most recent call to reserve()". Это одна вещь, что C++03 отличается от C++11. В C++03, один раз insert() вызывает размер вектора для достижения значение, указанное в предыдущем reserve() звонок (который вполне может быть меньше, чем ток capacity() С a reserve() может привести к большим capacity() чем просил), любые последующие insert() может привести к перераспределению и недействительности всех итераторов и ссылок. В C++11 этого не произойдет, и вы всегда можете доверять capacity() знать с уверенностью, что следующее перераспределение не произойдет до того, как размер путепроводов capacity().

в заключение, если вы работаете с C++03 вектор и вы хотите убедиться, что перераспределение не произойдет при выполнении вставки, это значение аргумента, который вы ранее передали в reserve() что вы должны проверить размер, а не возвращаемое значение вызова capacity(), в противном случае вы можете удивиться "преждевременное" перераспределение.

Comments

    Ничего не найдено.