Подтвердить что ты не робот

Итератор стирания вектора

У меня есть этот код:

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(), чтобы оператор неравенства не работал?

4b9b3361

Ответ 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));
    }
}

Это работает для меня. И не нужно думать, что индексы уже стерты.