python — C ++: push_back в std :: vector при его итерации

Следующий фрагмент кода дает очень странный вывод. Я ожидал переполнения (Python выдает MemoryError)

#include <iostream>
#include <vector>

int main()
{
std::vector<int> a{1,2,3};

for( auto const & item : a)
a.push_back(item);for( auto const & item : a)
std::cout<<item<<',';

return 0;
}

Выход: 1,2,3,1,0,3,

Как мне интерпретировать этот результат?

Если вы делаете подобное в Python, это приводит к ошибке памяти.

>>> a = range(0,20)
>>> for i in a:
a.append(i)Traceback (most recent call last):
File "<pyshell#3>", line 2, in <module>
a.append(i)
MemoryError

>>>

Этот вопрос пришел мне в голову, потому что вышеописанный способ написания кода считается безопасным. И для связанной безопасности контейнер не должен расти / сокращаться во время foreach type iteration, Итак, это дырявая абстракция.

Есть ли способ обернуть это foreach цикл, так что любая операция, вызывающая изменение / перераспределение размера, не допускается в теле цикла.

3

Решение

В C ++ добавление элементов в вектор может привести к перераспределению содержащихся данных, что сделает недействительными все итераторы. Это означает, что вы не можете зацикливаться на векторе, используя итераторы (что и делает цикл for на основе диапазона), а также вставлять новые элементы.

Вы Можно однако итерируйте с использованием индексов и используйте размер вектора в качестве условия, поскольку индексы всегда будут одинаковыми.

7

Другие решения

Если вектор будет изменен, итератор станет недействительным.

Вы могли бы сделать это, если вы бронируете заранее.

Имейте в виду, что for range будет работать на границах итератора, определенных до внесения каких-либо изменений. Так что получите только копию вашего списка в приложении.

#include <iostream>
#include <vector>

int main()
{
std::vector<int> a{1,2,3};

a.reserve(10);           // 10 should be enough to get a copy without reallocating
for( auto const & item : a)
a.push_back(item);

for( auto const & item : a)
std::cout<<item<<',';

return 0;
}

Выход:

1,2,3,1,2,3,

Я бы не рекомендовал такой подход, потому что я не считаю его чистым или ясным. Однако, если вы ссылаетесь на стандарт, ожидается следующее поведение:

23.3.6.5. Векторные модификаторы

Что касается использования insert,emplace,emplace_back, push_back,

Примечания: Вызывает перераспределение, если новый размер больше, чем старая емкость. Если перераспределение не происходит, все итераторы и ссылки до точки вставки остаются действительными.

То есть, если перераспределение не происходит, вы можете доверять своим итераторам до точки вставки. Так что, пока емкость вашего вектора достаточно высока, вы можете добавлять без проблем.

3

По вопросам рекламы [email protected]