进一步std ::设置困境

时间:2009-05-27 06:04:10

标签: c++ templates stl set

我先前问过this question。我对std :: set很感兴趣,但我有另一个令人困惑的场景。

即,以下代码是合法的,可移植的c ++ for T = std :: vector和T = std :: set:

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引用,set :: iterator和set :: const_iterator是相同的,所以我不知道这是否合法。但是,我似乎找不到另一种方法来获得我需要工作的操作,无论类型如何。我可以使用模板专业化,但是最好不要专注于第一名。

3 个答案:

答案 0 :(得分:2)

erase-remove idiom仅适用于序列容器。对于标准的关联容器,它不起作用,解决方案也不那么简单。

两种方法:

  1. 使用remove_copy_if复制所有内容 价值成另一个临时 容器然后交换内容 与那些原始容器的 暂时的。 [请将我的answer提交给相关的问题解答]
  2. 另一个是循环走路 当你将迭代器传递给擦除时,容器元素和post会增加迭代器。
  3. 有关详细信息,请参阅此问题:remove_if equivalent for std::map

    另外,请参阅第9项。选择Scott Meyers的Effective STL中的擦除选项。

答案 1 :(得分:1)

不,它不适用于std::set,因为std::remove()的一个要求是迭代器是一个可变迭代器,而std::set的迭代器是不可变的。

遗憾的是,我没有任何好的选择。您可以做的一件事是使用std::find()来查找元素出现的迭代器,然后在迭代器上使用.erase()方法(std::vector和{ {1}})删除它;并继续这样做,直到没有更多这样的元素。但这可能是非常低效的,O(n ^ 2)而不是O(n)。

答案 2 :(得分:0)

我认为“正确”的答案是remove_elements重载std::set。由于set是有序的并且不包含重复项,因此删除等于removed_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是你要问的唯一一个类,我认为这是你实际使用的唯一棘手的情况,至少目前是这样。如有必要,您可以使用特征根据容器的属性选择正确的算法版本。