2012-11-19 3 views
2

멀티 샘플에 항목을 삽입하는 샘플 코드가 있습니다. 지정된 키의 특정 항목을 삭제하려고합니다. 그러나이 코드는 무한 루프로 진행됩니다. 누군가이 코드를 도와 줄 수 있습니까?C++ STL 멀티 맵에서 특정 키의 항목 제거

#include <iostream> 
#include <map> 
#include <string> 
using namespace std; 

int main() 
{ 
    multimap<string, string> names; 
    string n; 

    names.insert(pair<string, string>("Z", "F")); 
    names.insert(pair<string, string>("Z", "A")); 

    names.insert(pair<string, string>("S", "T")); 
    names.insert(pair<string, string>("S", "A")); 
    names.insert(pair<string, string>("S", "J")); 

    names.insert(pair<string, string>("D", "H")); 
    names.insert(pair<string, string>("D", "W")); 
    names.insert(pair<string, string>("D", "R")); 

    multimap<string, string>::iterator p; 


    p = names.find("Z"); 
    if(p != names.end()) { // found a name 
     do { 
      cout << n << ", " << p->second; 
      cout << endl; 
      if (p->second.compare("A") == 0) { 
       names.erase(p); 
       p++; 
      } else { 
       p++; 
      } 
     } while (p != names.upper_bound("Z")); 
    } 
    else{ 
     cout << "Name not found.\n"; 
    } 

    p = names.find("Z"); 
    if(p != names.end()) { // found a name 
     do { 
      cout << n << ", " << p->second; 
      cout << endl; 
     } while (p != names.upper_bound("Z")); 
    } 
    else{ 
     cout << "Name not found.\n"; 
    } 
    return 0; 
} 

위의 경우 키 값 "Z"를 사용하여 "A"를 삭제하려고합니다.

multimap::erase

답변

5

따라서 그것을 무효화하고 잘못된 반복기를 증가하려고 소거 요소에 대한 반복자 때문에

names.erase(p); 
p++; 

는 P를 소거 라인을 무효화한다. p을 임시로 p를 증가시킨 다음 임시 반복기를 지우면 해결할 수 있습니다. 또한

multimap<string, string>::iterator temp = p; 
++p; 
names.erase(temp); 

당신이 C++ (11)를 사용하는 경우는 multimap::erase 컨테이너에

p = names.erase(p); 

편집을 다음 반복자를 반환 위에서 실제로 무한 루프의 소스 ​​아니다 . 두 번째 루프에서는 p을 증가시키지 않으므로 영원히 지속됩니다. 그러나 그것은 예측할 수 없으며 버그 추적이 어려울 수 있기 때문에 여전히 고쳐야 할 사항입니다.

+0

@brown 어떻게이 문제를 해결할 수 있습니까? iterator를 임시로 복사하고 해당 임시 반복기를 사용하여 지우려고했으나 작동하지 않았습니다. – Santhosh

+0

@ skokal01이 예제 수정으로 업데이트되었습니다. –

2

다른 사람들에 의해 말했듯이, 방금 지운 요소를 가리키는 반복자를 앞으로 나아가는 것이 보장되는 것은 아닙니다. C++ 11에서

names.erase(p++); 

당신은 대안으로 수익을 검색 할 수 있습니다 : 그것은을 삭제하기 전에 당신이 대신 할 수있는 것은 삭제 한 을 따라 요소에 반복자를 검색 할 접미사를 ++ 연산자를 사용하는 것입니다 또한 결코를 증가하지 않기 때문에 두 번째 루프는 정의에 의해 무한 루프이라고 이미 말했다되었습니다

p = names.erase(p); 

: 다음과 같은 요소를 가리키는 (또는 더 이상 요소가없는 경우 end()입니다) erase의 가치, 계수기.

그러나 요소의 범위에있는 마지막 요소에 도달했는지 확인하는 방법은 매우 효율적이지 않습니다. 루프의 모든 반복에서 upper_bound을 호출하면 반환되는 반복자는 항상 같지만 새로운 O (log (n)) 트리를 매번 검색합니다.

루프를 입력하고 결과를 저장하기 전에 upper_bound을 실행하여 분명히 향상시킬 수 있습니다. 그러나 더 나은, 당신이 한 번 equal_range 기능을 실행하는 게 좋을 것, 그리고 단순히 반환 범위를 반복 : C++ 11에서

typedef multimap<string,string>::const_iterator mapit; 
std::pair<mapit,mapit> range = names.equal_range("Z"); 
mapit it = range.first; 
while (it != range.second) 
    if (it->second == "A") 
    names.erase(it++); 
    else 
    ++it; 

auto의 사용이 더 나은 보이게됩니다.

관련 문제