Итератор правила о признании недействительными
каковы правила недействительности итератора для контейнеров C++?
желательно в формате сводного списка.
(Примечание:это должно быть запись в C++ FAQ Stack Overflow. Если вы хотите критиковать идею предоставления FAQ в этой форме, то публикация на meta, которая начала все это было бы место, чтобы сделать это. Ответы на этот вопрос отслеживаются в в C++ чат, где идея FAQ началась в во-первых, поэтому ваш ответ, скорее всего, будет прочитан теми, кто придумал эту идею.)
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()С areserve()может привести к большимcapacity()чем просил), любые последующиеinsert()может привести к перераспределению и недействительности всех итераторов и ссылок. В C++11 этого не произойдет, и вы всегда можете доверятьcapacity()знать с уверенностью, что следующее перераспределение не произойдет до того, как размер путепроводовcapacity().в заключение, если вы работаете с C++03 вектор и вы хотите убедиться, что перераспределение не произойдет при выполнении вставки, это значение аргумента, который вы ранее передали в
reserve()что вы должны проверить размер, а не возвращаемое значение вызоваcapacity(), в противном случае вы можете удивиться "преждевременное" перераспределение.
Comments