【问题标题】:Further std::set woes进一步的 std::set 问题
【发布时间】:2009-05-27 06:04:09
【问题描述】:

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

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

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 是一样的,所以我不知道这是否合法。但是,无论类型如何,我似乎都找不到另一种方法来获得我需要工作的操作。我可以求助于模板专业化,但是最好不必一开始就专门化。

【问题讨论】:

  • 在尝试这些事情之前,最好阅读 scott meyer 的有效 stl。特别是第 2 项:当心容器独立代码的错觉。有些东西不能通用,有些东西可能是可扩展性的问题。

标签: c++ templates stl set


【解决方案1】:

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

两种方法:

  1. 使用remove_copy_if复制所有 值到另一个临时 容器,然后交换内容 原来的容器与那些 临时的。 [参考我的answer相关Q]
  2. 另一个是循环行走 当你将它传递给擦除时,容器元素和 post 会增加迭代器。

更多详情请参考此Q:remove_if equivalent for std::map

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

【讨论】:

    【解决方案2】:

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

    很遗憾,我没有任何好的替代方案可供建议。您可以做的一件事是使用std::find() 查找元素出现的迭代器,然后在迭代器上使用.erase() 方法(在std::vectorstd::set 中都存在)来擦除它;并继续这样做,直到不再有这样的元素。但这可能效率很低,O(n^2) 而不是 O(n)。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-20
        • 1970-01-01
        • 1970-01-01
        • 2011-09-27
        • 2011-01-08
        • 2012-06-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多