В этом разделе описаны некоторые распространенные ошибки с<BOOST_FOREACH
>.
С тех пор<BOOST_FOREACH
>это макрос, он должен иметь ровно два аргумента, причем ровно одна запятая разделяет их. Это не всегда удобно, особенно когда тип переменной петли является шаблоном. Подумайте о том, чтобы попробовать<std::map
>:
std::map<int,int> m;
BOOST_FOREACH(std::pair<int,int> p, m)
Один из способов исправить это с помощью typedef.
std::map<int,int> m;
typedef std::pair<int,int> pair_t;
BOOST_FOREACH(pair_t p, m)
Другой способ исправить это - предварительно объявить переменную цикла:
std::map<int,int> m;
std::pair<int,int> p;
BOOST_FOREACH(p, m)
Под крышками<BOOST_FOREACH
>используются итераторы для прохождения последовательности элементов. Перед выполнением цикла конечный итератор кэшируется в локальной переменной. Это называетсяподъем, и это важная оптимизация. Однако предполагается, что конечный итератор последовательности стабилен. Обычно это так, но если мы изменяем последовательность, добавляя или удаляя элементы, пока мы повторяем ее, мы можем в конечном итоге подняться на свой собственный горшок.
Рассмотрим следующий код:
std::vector<int> vect(4, 4);
BOOST_FOREACH(int i, vect)
{
vect.push_back(i + 1);
}
Этот код будет компилироваться, но он имеет неопределенное поведение. Это объясняется тем, что логически это эквивалентно следующему:
std::vector<int> vect(4, 4);
for(std::vector<int>::iterator it1 = vect.begin(), it2 = vect.end();
it1 != it2; ++it1)
{
int i = *it1;
vect.push_back(i + 1);
}
Призыв к<vect.push_back()
>приведет к тому, что все итераторы в<vect
>станут недействительными, включая<it1
>и<it2
>. Следующая итерация через цикл приведет к использованию недействительных итераторов. Это плохие новости.
Мораль истории состоит в том, чтобы дважды подумать, прежде чем добавлять и удалять элементы из последовательности, над которой вы повторяете. Если это может привести к тому, что итераторы станут недействительными, не делайте этого. Вместо этого используйте обычный<for
>цикл.