Изменение содержимого вектора в BOOST_FOREACH - PullRequest
0 голосов
/ 26 ноября 2009

Этот вопрос касается того, как 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 () вычисляется только один раз (до цикла) при использовании вектора, но имеет более динамическую оценку при использовании списка?

Ответы [ 3 ]

6 голосов
/ 26 ноября 2009

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

http://www.boost.org/doc/libs/1_40_0/doc/html/foreach/pitfalls.html

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

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

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

2 голосов
/ 26 ноября 2009

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

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

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

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

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

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

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

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

0 голосов
/ 26 ноября 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...