2012-11-19 72 views
2

我有這個示例代碼將條目插入到multimap中。我試圖刪除指定鍵的特定條目。但是這段代碼進入了無限循環。有人可以幫我解決這個問題嗎?在C++中刪除特定鍵的條目STL multimap

#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」。

回答

5

multimap::erase無效任何迭代到擦除元素,所以該線

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

@dbrown,我該如何解決這個問題?我試着將迭代器複製到一個臨時的,並使用該臨時迭代器擦除,但它不起作用 – Santhosh

+0

@ skokal01更新了一個示例修復 –

2

正如其他人所說,推進一個指向剛剛被擦除的元素的迭代器並不能保證能夠正常工作。你可以做的反而是使用後綴++操作來獲取一個迭代隨後的擦寫元素也被刪除前:

names.erase(p++); 

在C++ 11,則可以選擇獲取回報的erase值,它指向以下元素(或者是end()如果沒有更多的元素):

p = names.erase(p); 

也有人已經說過,你的第二個循環是通過定義一個無限循環,因爲它永遠不會遞增計數器。

但是,還有一件事應該說:檢查是否已達到元素範圍中的最後一個元素的方法效率不高:在循環的每次迭代中都會調用upper_bound,這將導致每次都會搜索一個新的O(log(n))樹,儘管返回的迭代器總是相同的。

在進入循環並存儲結果之前,您可以通過運行upper_bound來明顯改善這一點。但更重要的,我建議你運行equal_range功能一次,然後只需通過它返回的範圍內循環:

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; 

在C++ 11,使用auto將使這更好看。