2014-06-10 40 views
1

我想所有項目迭代中std::multimap(所有所有鍵的值),並刪除滿足某個條件的所有條目:遍歷的std :: multimap中刪除某些條目

#include <map> 

typedef int KEY_TYPE; 
typedef int VAL_TYPE; 

bool shouldRemove(const KEY_TYPE&, const VAL_TYPE&); 

void removeFromMap(std::multimap<KEY_TYPE,VAL_TYPE>& map){ 
    for (auto it = map.begin(); it != map.end(); it++){ 
     if (shouldRemove(it->first,it->second)) 
      map.erase(it); 
    } 
} 

迭代工程除非第一個項目被刪除,並且拋出了以下錯誤,則:

地圖/套迭代器不遞增的

哪有removeFromMap函數被重寫以正常工作?該代碼應該適用於地圖的各種鍵和值類型。

我使用C++ 11和Visual Studio 2013年

+0

通常,使用map.erase(iterator)的返回值,因爲它會將迭代器返回到下一個元素或結束,如果它是最後一個元素 – AquilaRapax

+0

@Erbureth您應該將其添加爲答案:-) –

+0

@ KarlNicoll然而,深入挖掘之後,Erase-remove成語不適用於'std :: set','std :: map'和朋友,因爲它們的值類型不是'MoveAssignable'。我不知道如何在這種容器上實現它,因爲它通過轉換元素來工作。 – Erbureth

回答

5

你需要增加你的迭代你做擦除之前。當你做map.erase(it);迭代器it變得無效。但是,地圖中的其他迭代器仍然有效。因此,您可以通過在迭代器做一個後增量解決這個問題...

auto it = map.begin(); 
const auto end = map.end(); 

while (it != end) 
{ 
    if (shouldRemove(it->first,it->second)) 
    { 
     map.erase(it++); 
       // ^^ Note the increment here. 
    } 
    else 
    { 
     ++it; 
    } 
} 

應用於itmap.erase()參數內的後加將確保該項目是通過增加迭代消去後it仍然有效在擦除之前指向地圖中的下一個項目。

map.erase(it++); 

...在功能上等同於...

auto toEraseIterator = it; // Remember the iterator to the item we want to erase. 
++it;       // Move to the next item in the map. 
map.erase(toEraseIterator); // Erase the item. 

由於@imbtfab在評論中指出的那樣,你也可以用it = map.erase(it)做在C++ 11的同樣的事情,而不需要後增加。

還請注意,for循環現在已更改爲while循環,因爲我們正在手動控制迭代器。

此外,如果您希望使removeFromMap函數儘可能通用,則應考慮使用模板參數並直接傳遞迭代器,而不是將引用傳遞給多圖。這將允許您使用任何地圖樣式的容器類型,而不是強制multimap進入。

例如,

template <typename Iterator> 
void removeFromMap(Iterator it, const Iterator &end){ 
    ... 
} 

這是標準的C++函數<algorithm>如何做到這一點也(例如std::sort(...))。

+0

適合我,謝謝!但是,我不明白爲什麼使用後增加的方式可以修復問題 - 爲什麼要「擦除」(它);它++;'和'擦除(它++);'不同? – muffel

+1

當你擦除(它)時,變量'it'不再可用。試圖在擦除之後增加「it」是*未定義的行爲*。通過執行'erase(it ++)',你可以在* erase被調用之前遞增'it' *,但仍然會將舊的未遞增的迭代器傳遞到'erase'函數中。它相當於以下內容:'auto newIt = std :: next(it); map.erase(它); it = newIt;'。你可以通過[看到後增量操作符是如何工作的]來更好地理解(https://stackoverflow.com/questions/484462/difference-between-i-and-i-in-a-loop)。 –

+0

@Karl:在你的評論中,你想要'auto newIt = std :: next(it)'(或其他的東西)。你有什麼增加它並將增加的值賦給newIt。 –