c ++ error: векторный итератор + смещение вне диапазона. [Дубликат]

Если вы используете python 3 или выше,

>>> list(bytes(b'test'))
[116, 101, 115, 116]
437
задан Community 23 May 2017 в 10:31
поделиться

3 ответа

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


Вставка

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

  • vector: все итераторы и ссылки перед точкой вставки не затронуты, если новый размер контейнера больше, чем предыдущая емкость (в этом случае все итераторы и ссылки недействительным) [23.3.6.5/1]
  • 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: унаследовано от базового контейнера

Erasure

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

  • 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

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

Примечание 2

Функция

no swap () делает недействительными любые ссылки, указатели или итераторы, ссылающиеся на элементы контейнеров меняются местами. [Примечание: Итератор end () не ссылается ни на какой элемент, поэтому он может быть недействительным. -End note] [23.2.1 / 10]

Примечание 3

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

Примечание 4

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

318
ответ дан Community 18 August 2018 в 12:42
поделиться
  • 1
    Хорошая идея, просто замечание: я думаю, что контейнеры associative можно было сгруппировать в одну строку, и было бы целесообразно добавить еще одну строку неупорядоченных ассоциативных единиц ... хотя я не уверен, как перефразирующую часть можно сопоставить с вставкой / стиранием, знаете ли вы, как проверить, будет ли вызвана переадресация или нет? – Matthieu M. 22 June 2011 в 11:33
  • 2
    IIRC, где-то спецификация говорит, что конечный итератор не является итератором & quot; к объектам внутри этого контейнера & quot ;. Интересно, как эти гарантии ищут конечный итератор в каждом случае? – Johannes Schaub - litb 22 June 2011 в 13:57
  • 3
    Помимо swap(), каковы правила действительности итератора при копировании / перемещении? – goodbyeera 8 March 2014 в 04:35
  • 4
    @goodbyeera: Скопировать / перенести назначение чего? – Lightness Races in Orbit 8 March 2014 в 13:11
  • 5
    @LightnessRacesinOrbit: Как вставка, стирание, изменение размера и своп, копирование / перемещение также являются функциями-членами std :: vector, поэтому я думаю, что вы могли бы также предоставить им правила итеративности. – goodbyeera 8 March 2014 в 13:17
  • 6
    Я думаю, что я сделал ошибку, потому что std::basic_string, похоже, не считается контейнером и, конечно, не является контейнером в разделе стандарта, к которому относится примечание. Тем не менее, где говорится, что SSO запрещен (я знаю, что COW)? – Deduplicator 10 September 2014 в 22:35
  • 7
    @MuhammadAnnaqeeb: Этот ответ, по общему признанию, не дает ясности, поскольку я взял ярлык, но намерение сказать, что изменение размера является вставкой / стиранием, как и в случае необходимости перераспределения, вы можете рассмотреть это будет то же самое, что и стирание, а затем повторное включение всех затронутых элементов. Разумеется, эта часть ответа может быть улучшена. – Lightness Races in Orbit 19 April 2015 в 02:46
  • 8
    @Yakk: Но это не так; см. цитированный стандартный текст. Похоже, это было исправлено на C ++ 11. :) – Lightness Races in Orbit 26 May 2015 в 16:11
  • 9
    Являются ли эти правила одинаковыми в C ++ 14? C ++ 17 (насколько это известно сейчас)? – einpoklum 10 January 2016 в 18:28
  • 10
    @metamorphosis: deque хранит данные в несмежных блоках. Вставка в начале или конце может выделять новый блок, но никогда не перемещается вокруг предыдущих элементов, поэтому указатели остаются действительными. Но правила перехода к следующему / предыдущему элементу изменяются, если выделен новый блок, поэтому итераторы являются недействительными. – Kundor 16 April 2016 в 17:39

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

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

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

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

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

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

34
ответ дан AnT 18 August 2018 в 12:42
поделиться

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

C ++ 03:

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

C ++ 11:

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

Итак, в 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(), поскольку reserve() может привести к большему capacity(), чем просили), любой последующий insert() может привести к перераспределению и аннулированию всех итераторов и ссылок. В C ++ 11 этого не произойдет, и вы всегда можете доверять capacity() с уверенностью знать, что следующее перераспределение не произойдет до того, как размер превысит capacity().

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

19
ответ дан neverhoodboy 18 August 2018 в 12:42
поделиться
  • 1
    Тем не менее, я бы застрелил любого компилятора, который сделал это со мной, и никакие жюри на суше не осудили бы меня. – Yakk - Adam Nevraumont 2 May 2014 в 15:39
  • 2
    Я не «не заметил», это; это была редакционная ошибка в C ++ 03, которая была исправлена ​​на C ++ 11. Отсутствие компилятора основного потока использует ошибку. – Lightness Races in Orbit 14 November 2014 в 00:49
  • 3
    @Yakk Я думаю, что gcc уже делает недействительными итераторы в таких ситуациях. – ShreevatsaR 25 November 2016 в 00:15
Другие вопросы по тегам:

Похожие вопросы: