Как удалить с карты при ее повторении?

Как удалить с карты во время ее итерации? как:

std::map map; for(auto i : map) if(needs_removing(i)) // remove it from the map 

Если я использую map.erase это приведет к аннулированию iteratorов

Стандартный идентификатор стирания ассоциативного контейнера:

 for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */) { if (must_delete) { m.erase(it++); // or "it = m.erase(it)" since C++11 } else { ++it; } } 

Обратите внимание, что мы действительно хотим использовать обычный цикл, потому что мы модифицируем сам контейнер. Цикл, основанный на диапазоне, должен быть строго зарезервирован для ситуаций, когда мы заботимся только об элементах. Синтаксис RBFL делает это ясным, даже не подвергая контейнер внутри тела цикла.

Редактировать. Pre-C ++ 11, вы не могли стереть константы-константы. Там вы должны сказать:

 for (std::map::iterator it = m.begin(); it != m.end(); ) { /* ... */ } 

Стирание элемента из контейнера не противоречит константе элемента. По аналогии, всегда было совершенно законно delete p где p – указатель на константу. Константа не ограничивает время жизни; const в C ++ все еще могут перестать существовать.

Я лично предпочитаю этот шаблон, который немного яснее и проще, за счет дополнительной переменной:

 for (auto it = m.cbegin(), next_it = m.cbegin(); it != m.cend(); it = next_it) { next_it = it; ++next_it; if (must_delete) { m.erase(it); } } 

Преимущества такого подхода:

  • инкрементатор цикла for имеет смысл как инкремент;
  • операция стирания – это простое удаление, а не смешивание с логикой нарастания;
  • после первой строки тела цикла значение it и next_it остается фиксированным на протяжении всей итерации, что позволяет вам легко добавлять дополнительные инструкции, ссылаясь на них, без учета того, будут ли они работать по назначению (за исключением того, что вы не можете использовать it после стирание).

Короче говоря: «Как удалить с карты при ее повторении?»

  • С помощью старой карты impl: вы не можете
  • С новой привязкой к карте: почти так же, как предложил @KerrekSB. Но есть некоторые проблемы с синтаксисом в том, что он опубликовал.

Из GCC map impl (примечание GXX_EXPERIMENTAL_CXX0X ):

 #ifdef __GXX_EXPERIMENTAL_CXX0X__ // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 130. Associative erase should return an iterator. /** * @brief Erases an element from a %map. * @param position An iterator pointing to the element to be erased. * @return An iterator pointing to the element immediately following * @a position prior to the element being erased. If no such * element exists, end() is returned. * * This function erases an element, pointed to by the given * iterator, from a %map. Note that this function only erases * the element, and that if the element is itself a pointer, * the pointed-to memory is not touched in any way. Managing * the pointer is the user's responsibility. */ iterator erase(iterator __position) { return _M_t.erase(__position); } #else /** * @brief Erases an element from a %map. * @param position An iterator pointing to the element to be erased. * * This function erases an element, pointed to by the given * iterator, from a %map. Note that this function only erases * the element, and that if the element is itself a pointer, * the pointed-to memory is not touched in any way. Managing * the pointer is the user's responsibility. */ void erase(iterator __position) { _M_t.erase(__position); } #endif 

Пример со старым и новым стилем:

 #include  #include  #include  #include  using namespace std; typedef map t_myMap; typedef vector t_myVec; int main() { cout << "main() ENTRY" << endl; t_myMap mi; mi.insert(t_myMap::value_type(1,1)); mi.insert(t_myMap::value_type(2,1)); mi.insert(t_myMap::value_type(3,1)); mi.insert(t_myMap::value_type(4,1)); mi.insert(t_myMap::value_type(5,1)); mi.insert(t_myMap::value_type(6,1)); cout << "Init" << endl; for(t_myMap::const_iterator i = mi.begin(); i != mi.end(); i++) cout << '\t' << i->first << '-' << i->second << endl; t_myVec markedForDeath; for (t_myMap::const_iterator it = mi.begin(); it != mi.end() ; it++) if (it->first > 2 && it->first < 5) markedForDeath.push_back(it->first); for(size_t i = 0; i < markedForDeath.size(); i++) // old erase, returns void... mi.erase(markedForDeath[i]); cout << "after old style erase of 3 & 4.." << endl; for(t_myMap::const_iterator i = mi.begin(); i != mi.end(); i++) cout << '\t' << i->first << '-' << i->second << endl; for (auto it = mi.begin(); it != mi.end(); ) { if (it->first == 5) // new erase() that returns iter.. it = mi.erase(it); else ++it; } cout << "after new style erase of 5" << endl; // new cend/cbegin and lambda.. for_each(mi.cbegin(), mi.cend(), [](t_myMap::const_reference it){cout << '\t' << it.first << '-' << it.second << endl;}); return 0; } 

печатает:

 main() ENTRY Init 1-1 2-1 3-1 4-1 5-1 6-1 after old style erase of 3 & 4.. 1-1 2-1 5-1 6-1 after new style erase of 5 1-1 2-1 6-1 Process returned 0 (0x0) execution time : 0.021 s Press any key to continue. 

Довольно грустно, а? Обычно я делаю это, создавая контейнер iteratorов вместо удаления во время обхода. Затем пройдите через контейнер и используйте map.erase ()

 std::map map; std::list< std::map::iterator > iteratorList; for(auto i : map ){ if ( needs_removing(i)){ iteratorList.push_back(i); } } for(auto i : iteratorList){ map.erase(*i) } 

Предполагая, что C ++ 11, это тело однострочного цикла, если это соответствует вашему стилю программирования:

 using Map = std::map; Map map; // Erase members that satisfy needs_removing(itr) for (Map::const_iterator itr = map.cbegin() ; itr != map.cend() ; ) itr = needs_removing(itr) ? map.erase(itr) : std::next(itr); 

Пара других незначительных изменений стиля:

  • Показывать объявленный тип ( Map::const_iterator ), когда это возможно / удобно, с использованием auto .
  • Использовать для типов шаблонов, чтобы облегчить чтение / поддержку вспомогательных типов ( Map::const_iterator ).
  • Ограничить прокрутку MKMapView
  • Android MapActivity: не удалось получить соединение с заводским клиентом
  • Scala: Почему mapValues ​​создает представление и есть ли стабильные альтернативы?
  • Карта, которая может быть итерирована в порядке значений
  • Какой самый быстрый способ изменить ключ элемента внутри std :: map
  • Scala: карта слияния
  • Как я могу перебирать карту из ?
  • Создание карты :: поиск недействителен
  • Есть ли у Java HashMap с обратным поиском?
  • Какие требования должны соответствовать classам classов std :: map?
  • Scala лучший способ превратить коллекцию в Map-by-key?
  • Давайте будем гением компьютера.