Добавление вектора std::с его собственными элементами с помощью итераторов
Следующий код работает как ожидалось (тест проходит), но мне интересно, считается ли работа с итераторами таким образом плохой практикой в c++ или это нормально.
Может быть, это специфично для std::vector
, а другие коллекции ведут себя по-разному, и рекомендации различаются между коллекциями (или даже их реализациями)?
Это, конечно, не в порядке в других языках, и большую часть времени изменение коллекции сделает недействительными итераторы и бросит исключения.
BOOST_AUTO_TEST_CASE (ReverseIteratorExample) {
std::vector<int> myvector;
for(int i = 0; i < 5; i++)
{
myvector.push_back(i);
}
// is this generally a bad idea to change the vector while iterating?
// is it okay in this specific case?
myvector.reserve(myvector.size() + myvector.size() - 2 );
myvector.insert(myvector.end(), myvector.rbegin() + 1, myvector.rend() -1);
int resultset [8] = { 0,1,2,3,4,3,2,1 };
std::vector<int> resultVector( resultset, resultset + sizeof(resultset)/sizeof(resultset[0]) );
BOOST_CHECK_EQUAL_COLLECTIONS(myvector.begin(), myvector.end(), resultVector.begin(), resultVector.end());
}
Обобщенные Вопросы:
- это вообще плохая идея, чтобы изменить вектор во время итерации?
- это нормально в данном конкретном случае?
- является ли это специфичным для
std::vector
и других коллекций, которые ведут себя по-разному? - различаются ли лучшие практики между коллекциями (или даже их реализациями)?
1 ответ:
Это недопустимый код. Стандартное определение операций над состояниями контейнеров последовательностей (23.2.3@4):
Таким образом, ваш код вызывает неопределенное поведение, потому что он нарушает предварительное условие для операцииA. вставить(p, i, j) - [...] pre: i и j не являются итераторами в a.
insert
.Если вместо использования
insert
, вы написали цикл итерации отmyvector.rbegin() + 1
доmyvector.rend() -1
и вызвалиpush_back
по всем значениям, ваш код будет действителен: это потому, чтоpush_back
только делает недействительными векторные итераторы, если требуется перераспределение, и ваш вызовreserve
гарантирует, что это не так.В целом, хотя есть некоторые случаи, когда изменение контейнера во время итерации над ним нормально (например, цикл, описанный выше), вы должны убедиться, что ваши итераторы не являются недействительными при этом. Когда это происходит, зависит от каждого контейнера.