처음부터 끝까지 반복하는 동안지도 요소에서 erase ()를 호출하면 어떻게됩니까? 맵을 반복하고 요소를 지워야하는지

다음 코드에서는 맵을 반복하고 요소를 지워야하는지 테스트합니다. 요소를 지우고 계속 반복하는 것이 안전합니까 아니면 다른 컨테이너에서 키를 수집하고 두 번째 루프를 수행하여 erase ()를 호출해야합니까?

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it;
for (pm_it = port_map.begin(); pm_it != port_map.end(); pm_it++)
{
    if (pm_it->second == delete_this_id) {
        port_map.erase(pm_it->first);
    }
}

업데이트 : 물론, 나는 관련이 없다고 생각했지만 내 질문에 대답하는 이 질문읽었습니다 .



답변

C ++ 11

이것은 C ++ 11에서 수정되었습니다 (또는 모든 컨테이너 유형에서 지우기가 향상되거나 일관되게되었습니다).
erase 메소드는 이제 다음 반복자를 리턴합니다.

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
    }
}


답변

내가하는 방법은 다음과 같습니다 …

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 ...
     }
}


답변

이것이 내가 대략하는 방법입니다.

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

하지만 방금 예제 코드에서 복사했습니다.


답변