Вопрос

Этот вопрос касается того, как BOOST_FOREACH проверяет завершение цикла

cout << "Testing BOOST_FOREACH" << endl;
vector<int> numbers; numbers.reserve(8);
numbers.push_back(1); numbers.push_back(2); numbers.push_back(3);
cout << "capacity = " << numbers.capacity() << endl;
BOOST_FOREACH(int elem, numbers)
{
    cout << elem << endl;
    if (elem == 2) numbers.push_back(4); 
}
cout << "capacity = " << numbers.capacity() << endl;

дает вывод

Testing BOOST_FOREACH
capacity = 8
1
2
3
capacity = 8

Но как насчет числа 4, которое было вставлено в середине цикла? Если я изменю тип на список, вновь вставленный номер будет повторен. Операция векторного push_back сделает недействительными любые указатели, ЕСЛИ требуется перераспределение, однако в этом примере этого не происходит. Поэтому вопрос, который я предполагаю, заключается в том, почему итератор end () вычисляется только один раз (перед циклом) при использовании вектора, но имеет более динамическую оценку при использовании списка?

Это было полезно?

Решение

  

Под обложками BOOST_FOREACH использует   итераторы для прохождения элемента   последовательность. Перед выполнением цикла   конечный итератор кэшируется в локальном   переменная. Это называется подъем, и   это важная оптимизация. Это   предполагает, однако, что конец   Итератор последовательности стабилен. Это   как правило, но если мы изменим   последовательность путем добавления или удаления   элементы в то время как мы перебираем   это, мы можем в конечном итоге поднять себя   на нашей собственной петарде.

http://www.boost.org/ DOC / LIBS / 1_40_0 / DOC / HTML / Еогеасп / pitfalls.html

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

http://www.cplusplus.com/reference/stl/vector/resize /

Обратите внимание, что тогда вы не захотите push_back, а вместо этого будете использовать оператор []. Но будьте осторожны, выходя за пределы.

Другие советы

В комментариях был поднят вопрос, почему среда выполнения отладки Microsoft поднимает утверждение во время итерации по вектору, но не по списку. Причина в том, что insert определяется по-разному для list и vector (обратите внимание, что push_back является просто вставить в конец последовательности).

В соответствии со стандартом C ++ (ISO / IEC 14882: 2003 23.2.4.3, векторные модификаторы ):

  

[при вставке], если перераспределение не происходит, все итераторы и ссылки до точки вставки остаются действительными.

(23.2.2.3, модификаторы списка ):

  

[insert] не влияет на достоверность итераторов и ссылок.

Итак, если вы используете push_back (и уверены, что это не приведет к перераспределению), то в любом контейнере можно продолжить использование итератора для итерации по остальной части последовательности.

Однако в случае вектора неопределенное поведение использовать итератор end , который вы получили до push_back .

Это окольный ответ на вопрос; это прямой ответ на обсуждение в комментариях к вопросу.

foreach boost прекратит работу, когда будет выполнен итератор == numbers.end ()

Будьте осторожны, вызов push_back может / сделает недействительными все ваши текущие итераторы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top