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

Как я могу удалить элементы std:: map с помощью итератора?

Я хотел бы выполнить цикл std::map и удалить элементы на основе их содержимого. Как это лучше всего сделать?

4b9b3361

Ответ 1

Если у вас есть компилятор, совместимый с С++ 11, вот простой способ сделать это:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       itr = myMap.erase(itr);
    } else {
       ++itr;
    }
}

Идея состоит в том, чтобы переместить итератор вперед от начала контейнера до конца, проверяя на каждом шаге, должна ли быть удалена текущая пара ключей/значений. Если это так, мы удалим элемент, итератированный с помощью функции члена erase, который затем возвращает итератор в следующий элемент на карте. В противном случае мы заранее продвигаем итератор вперед.

Если у вас нет компилятора, совместимого с С++ 11, или вы работаете со старой кодовой базой, все немного сложнее. До С++ 11 функция-член erase не возвращала итератор в следующий элемент на карте. Это означало, что для удаления элемента во время итерации вам нужно будет использовать танцы из трех частей:

  • Скопировать текущий итератор.
  • Перенесите текущий итератор на следующий элемент.
  • Вызов erase на копии старого итератора.

Это показано здесь:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       std::map<K, V>::iterator toErase = itr;
       ++itr;
       myMap.erase(toErase);
    } else {
       ++itr;
    }
}

Этот процесс потребовался, потому что, если вы просто вызвали erase на итераторе, вы сделали бы его недействительным, что означает, что операции, такие как приращение и декремент, приведут к поведению undefined. Вышеприведенный код обойдется в этом, установив копию итератора, продвигая itr, чтобы он появился в следующем элементе, а затем удалил временную копию итератора.

Используя некоторую умную хитрость, можно уменьшить этот код за счет удобочитаемости. Следующий шаблон распространен в старшем С++-коде, но в С++ 11 не требуется:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       myMap.erase(itr++);  // <--- Note the post-increment!
    } else {
       ++itr;
    }
}

Использование оператора post-increment - это умный способ сделать копию старого итератора (помните, что оператор postfix ++ возвращает копию исходного значения итератора), а также продвигая старый итератор.

Ответ 2


Это простой способ:

    int value_to_delete( 2 );
    for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
        if( i->second != value_to_delete ) {
            mm.erase( i++ ); // advance before iterator become invalid
        }
        else {
            ++i;
        }
    }

Ответ 3

for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
  if(mycondition(it))
    it = mymap.erase(it);
  else
    it++;
}

edit: похоже, что это работает только в MSVC

edit2: в С++ 0x это тоже работает для ассоциативных контейнеров