Что происходит, если Вы называете стирание () на элементе карты, в то время как итерация от начинает заканчиваться?

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null.

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

132
задан Community 23 May 2017 в 12:25
поделиться

3 ответа

C++ 11

Это было зафиксировано в C++ 11 (или стирание улучшалось/делалось последовательное через все контейнерные типы).
метод стирания теперь возвращает следующий итератор.

auto pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        pm_it = port_map.erase(pm_it);
    }
    else
    {
        ++pm_it;
    }
}

C++ 03

Стирающиеся элементы в карте не делает недействительным итераторов.
(кроме итераторов на элементе, который был удален)

На самом деле вставка или удаление не делают недействительным ни одного из итераторов:

Также см. этот ответ:
Mark Ransom Technique

, Но действительно необходимо обновить код:
В Вашем коде Вы увеличиваете pm_it после называния стирания. В этой точке это слишком поздно и уже делается недействительным.

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        port_map.erase(pm_it++);  // Use iterator.
                                  // Note the post increment.
                                  // Increments the iterator but returns the
                                  // original value for use by erase 
    }
    else
    {
        ++pm_it;           // Can use pre-increment in this case
                           // To make sure you have the efficient version
    }
}
183
ответ дан 24 November 2019 в 00:11
поделиться

Это - то, как я сделал бы это, приблизительно:

bool is_remove( pair<string, SerialdMsg::SerialFunction_t> val )
{
    return val.second == delete_this_id;
}

map<string, SerialdMsg::SerialFunction_t>::iterator new_end = 
    remove_if (port_map.begin( ), port_map.end( ), is_remove );

port_map.erase (new_end, port_map.end( ) );

существует что-то нечетное приблизительно

val.second == delete_this_id

, но я просто скопировал его с Вашего примера кода.

1
ответ дан 24 November 2019 в 00:11
поделиться

Вот как я это делаю ...

typedef map<string, string>   StringsMap;
typedef StringsMap::iterator  StrinsMapIterator;

StringsMap m_TheMap; // Your map, fill it up with data    

bool IsTheOneToDelete(string str)
{
     return true; // Add your deletion criteria logic here
}

void SelectiveDelete()
{
     StringsMapIter itBegin = m_TheMap.begin();
     StringsMapIter itEnd   = m_TheMap.end();
     StringsMapIter itTemp;

     while (itBegin != itEnd)
     {
          if (IsTheOneToDelete(itBegin->second)) // Criteria checking here
          {
               itTemp = itBegin;          // Keep a reference to the iter
               ++itBegin;                 // Advance in the map
               m_TheMap.erase(itTemp);    // Erase it !!!
          }
          else
               ++itBegin;                 // Just move on ...
     }
}
12
ответ дан 24 November 2019 в 00:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: