2008-10-07 38 views
28

我大致有以下代碼。這可以做得更好或更高效?也許使用std::remove_if?你可以在遍歷它的時候從地圖中移除物品嗎?我們可以避免使用臨時地圖嗎?如何從std :: map過濾項目?

typedef std::map<Action, What> Actions; 
static Actions _actions; 

bool expired(const Actions::value_type &action) 
{ 
    return <something>; 
} 

void bar(const Actions::value_type &action) 
{ 
    // do some stuff 
} 

void foo() 
{ 
    // loop the actions finding expired items 
    Actions actions; 
    BOOST_FOREACH(Actions::value_type &action, _actions) 
    { 
    if (expired(action)) 
     bar(action); 
    else 
     actions[action.first]=action.second; 
    } 
    } 
    actions.swap(_actions); 
} 

回答

30

您可以使用erase(),但我不知道BOOST_FOREACH如何處理無效的迭代器。 documentation for map::erase指出只有被擦除的迭代器會失效,其他應該沒問題。下面是我將如何重組內部循環:即沒有人似乎知道的是,擦除返回一個新的,保證要被-有效的迭代,任何容器上使用時

Actions::iterator it = _actions.begin(); 
while (it != _actions.end()) 
{ 
    if (expired(*it)) 
    { 
    bar(*it); 
    Actions::iterator toerase = it; 
    ++it; 
    _actions.erase(toerase); 
    } 
    else 
    ++it; 
} 
+0

謝謝,這大概是我想出了太 – 2008-10-07 22:06:38

1

如果想法是刪除過期的項目,爲什麼不使用map::erase?通過這種方式,您只需刪除不再需要的元素,而不是使用所有要保留的元素來重建整個副本。

這樣做的方式是保存指向要擦除的元素的迭代器,然後在迭代結束後將其全部擦除。或者,您可以保存您訪問的元素,移動到下一個元素,然後清除臨時元素。雖然循環邊界在你的情況下會變得混亂,所以你必須自己微調迭代。

根據過期()如何實現,可能還有其他更好的方法。例如,如果您將時間戳追蹤爲地圖的關鍵字(如expired()所暗示的那樣),則可以對當前時間戳執行upper_bound,並且範圍[begin(),upper_bound())中的所有元素都需要被處理和刪除。

1

東西。

Actions::iterator it = _actions.begin(); 
while (it != _actions.end()) 
{ 
    if (expired(*it)) 
    { 
    bar(*it); 
    it = _actions::erase(it); 
    } 
    else 
    ++it; 
} 

存儲actions.end()可能不是在這種情況下,因爲迭代器的穩定性不能保證一個好的計劃,我相信。

+0

根據我在響應鏈接,刪除返回void的文件,你的代碼示例將無法編譯。 – 2008-10-07 22:25:34

+0

這是VC++的一個擴展,我認爲 – 2008-10-07 23:08:58

51

馬克Ransom算法的變體,但不需要臨時。

for(Actions::iterator it = _actions.begin();it != _actions.end();) 
{ 
    if (expired(*it)) 
    { 
     bar(*it); 
     _actions.erase(it++); // Note the post increment here. 
           // This increments 'it' and returns a copy of 
           // the original 'it' to be used by erase() 
    } 
    else 
    { 
     ++it; // Use Pre-Increment here as it is more effecient 
       // Because no copy of it is required. 
    } 
}