Итератор стирания вектора
У меня есть этот код:
int main()
{
vector<int> res;
res.push_back(1);
vector<int>::iterator it = res.begin();
for( ; it != res.end(); it++)
{
it = res.erase(it);
//if(it == res.end())
// return 0;
}
}
"Итератор произвольного доступа, указывающий на новое местоположение элемента, который следует за последним элементом, стертым при вызове функции, то есть конец вектора, если операция стерла последний элемент в последовательности."
Этот код дает сбой, но если я использую часть if(it == res.end())
и затем возвращаюсь, это работает. Как придешь? Кэширует ли цикл for res.end()
, чтобы оператор неравенства не работал?
Ответы
Ответ 1
res.erase(it)
всегда возвращает следующий допустимый итератор, если вы удалите последний элемент, он будет указывать на .end()
В конце цикла ++it
всегда вызывается, поэтому вы увеличиваете .end()
, что недопустимо.
Просто проверка на .end()
по-прежнему оставляет ошибку, поскольку вы всегда пропускаете элемент на каждой итерации (it
получает "incremented" по возврату от .erase()
, а затем снова по циклу)
Вероятно, вы хотите что-то вроде:
while (it != res.end()) {
it = res.erase(it);
}
чтобы стереть каждый элемент
(для полноты: я предполагаю, что это упрощенный пример, если вы просто хотите, чтобы каждый элемент ушел без выполнения операции над ним (например, удаление), вы должны просто вызвать res.clear()
)
Когда вы только условно стираете элементы, вы, вероятно, хотите что-то вроде
for ( ; it != res.end(); ) {
if (condition) {
it = res.erase(it);
} else {
++it;
}
}
Ответ 2
for( ; it != res.end();)
{
it = res.erase(it);
}
или, более общий:
for( ; it != res.end();)
{
if (smth)
it = res.erase(it);
else
++it;
}
Ответ 3
Как модификация ответа на crazylammer, я часто использую:
your_vector_type::iterator it;
for( it = res.start(); it != res.end();)
{
your_vector_type::iterator curr = it++;
if (something)
res.erase(curr);
}
Преимущество этого в том, что вам не нужно беспокоиться о том, чтобы забыть увеличивать свой итератор, делая его менее подверженным ошибкам, когда у вас сложная логика. Внутри цикла, curr никогда не будет равен res.end(), и он будет в следующем элементе независимо от того, удалите ли вы его из вашего вектора.
Ответ 4
Поскольку метод erase in vector возвращает следующий итератор переданного итератора.
Я приведу пример удаления элемента в векторе при итерации.
void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
//method 1
for(auto it = vecInt.begin();it != vecInt.end();){
if(*it % 2){// remove all the odds
it = vecInt.erase(it); // note it will = next(it) after erase
} else{
++it;
}
}
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
// recreate vecInt, and use method 2
vecInt = {0, 1, 2, 3, 4, 5};
//method 2
for(auto it=std::begin(vecInt);it!=std::end(vecInt);){
if (*it % 2){
it = vecInt.erase(it);
}else{
++it;
}
}
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
// recreate vecInt, and use method 3
vecInt = {0, 1, 2, 3, 4, 5};
//method 3
vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(),
[](const int a){return a % 2;}),
vecInt.end());
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
}
выведите aw ниже:
024
024
024
Более метод генерации:
template<class Container, class F>
void erase_where(Container& c, F&& f)
{
c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)),
c.end());
}
void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
//method 4
auto is_odd = [](int x){return x % 2;};
erase_where(vecInt, is_odd);
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
}
Ответ 5
Не стирайте, а затем увеличивайте итератор. Нет необходимости увеличивать, если у вашего вектора есть странное (или даже не знаю) количество элементов, которые вы пропустите конец вектора.
Ответ 6
Инструкция it ++ выполняется в конце блока. Поэтому, если вы удаляете последний элемент, вы пытаетесь увеличить итератор, указывающий на пустую коллекцию.
Ответ 7
Вы увеличиваете it
за конец (пустого) контейнера в выражении цикла цикла цикла.
Ответ 8
Также, похоже, работает следующее:
for (vector<int>::iterator it = res.begin(); it != res.end(); it++)
{
res.erase(it--);
}
Не уверен, есть ли в этом недостатки?
Ответ 9
if(allPlayers.empty() == false) {
for(int i = allPlayers.size() - 1; i >= 0; i--)
{
if(allPlayers.at(i).getpMoney() <= 0)
allPlayers.erase(allPlayers.at(i));
}
}
Это работает для меня. И не нужно думать, что индексы уже стерты.