2009-05-27 44 views
2

我問this question更早。我對std :: set很感興趣,但是我有另一個令人困惑的場景。進一步std :: set困境

即,是以下代碼法律,便攜式C++爲T =標準::向量和T =標準::設置:

template <typename T> 
void remove_elements(T& collection, int removal_value) 
{ 
    typename T::iterator new_end = 
     std::remove(collection.begin(), collection.end(), removal_value); 
    collection.erase(new_end, collection.end()); 
} 

按照SGI參考,設置:迭代並設置:: const_iterator是一樣的,所以我不知道這是否合法。但是,我似乎無法找到另一種方式來獲得我需要的操作,而不管類型如何。我可以求助於模板專業化,但是不必專注於第一個地方是很好的。

+3

在嘗試這些事情之前,最好先閱讀斯科特邁爾的有效期。特別是第2項:注意容器無關代碼的錯覺。有些東西不能通用,有些則可能是可擴展性的問題。 – stefaanv 2009-05-27 07:29:58

回答

2

erase-remove idiom僅適用於序列容器。對於標準的關聯容器,它不起作用,解決方案也不那麼簡單。

兩種方法:

  1. 使用remove_copy_if所有 值複製到另一個臨時 容器,然後交換內容的原始容器 臨時其中的一個 。 [請參閱我的answer相關的問題]
  2. 另一個將循環走 容器元素和後遞增迭代器時,您將它傳遞擦除。

請參考這個問答瞭解更多詳情:remove_if equivalent for std::map

同時,請參閱第9項中斯科特邁爾斯擦除從有效STL選項仔細選擇。

1

不,它不適用於std::set,因爲std::remove()的要求之一是迭代器是可變迭代器,並且std::set的迭代器不可變。

不幸的是,我沒有任何好的選擇建議。你可以做的一件事可能是使用std::find()來查找出現元素的迭代器,然後在迭代器上使用.erase()方法(它存在於std::vectorstd::set中)以清除它;並繼續這樣做,直到沒有更多這樣的元素。但是這可能是非常低效的,O(n^2)而不是O(n)。

0

我認爲「正確的」答案是過載remove_elementsstd::set。由於set是有序的並且不包含重複項,因此刪除等於removal_value的元素要比對於矢量或泛型序列簡單得多。你不是真的想用一切相同的算法,即使你可以:

template <typename T> 
void remove_elements(T& collection, const typename T::value_type& removal_value) 
{ 
    typename T::iterator new_end = 
     std::remove(collection.begin(), collection.end(), removal_value); 
    collection.erase(new_end, collection.end()); 
} 

template<typename T> 
void remove_elements(std::set<T>& collection, const T& removal_value) 
{ 
    collection.erase(removal_value); 
} 

我稍微關心這些是否曾經曖昧,但最明顯的用途情況下,他們似乎工作確定爲了我。

如果你有其他的獨立排序關聯容器比std :: set要擔心,這有點痛苦。您正在進入std :: swap領域,您所實現的每個類都必須提供remove_elements的重載。但是既然set是你問的唯一的類,我認爲這是你實際使用的唯一棘手的情況,至少現在是這樣。如有必要,可以使用特徵根據容器的屬性選擇正確的算法版本。