【问题标题】:How to overload std::remove for std::list?如何为 std::list 重载 std::remove?
【发布时间】:2013-04-17 14:42:27
【问题描述】:

我曾经了解到,从容器中擦除元素的一般方法是通过erase-remove-idiom。但我惊讶地发现,至少 g++ 的 STL 实现不会为 std::list 重载 std::remove(),因为在这种情况下,可以通过指针操作进行重新排序来保存很多对象分配。

C++ 标准是否有理由不要求进行这种优化?但我的主要问题是如何重载 std::remove() (它不必可移植到 g++ 之外),所以我可以提供一个使用 list::splice()/list::merge() 的实现。我尝试了几个签名,但充其量是一个模棱两可的错误,例如:

template <typename T>
typename std::list<T>::iterator
remove(typename std::list<T>::iterator first,
       typename std::list<T>::iterator last, const T &v);

P.S.:对不起,我不够清楚。请忽略这些函数来自 std 命名空间以及它们的具体作用。我只是想了解更多关于 C++ 中的模板/类型特征/重载规则。

【问题讨论】:

标签: c++ templates stl


【解决方案1】:

这不是强制性的,因为它不仅仅是一种优化,它的语义与您对序列容器的期望不同:

std::list<int> l;
l.push_back(1);
l.push_back(2);

std::list<int>::iterator one = l.begin();
std::list<int>::iterator two = l.end(); --two;

if (something) {
    l.erase(remove(l.begin(), l.end(), 1), l.end());
    // one is still valid and *one == 2, two has been invalidated
} else {
    l.remove(1);
    // two is still valid and *two == 2, one has been invalidated
}

关于实际问题:ISWYM,我暂时不知道如何编写一对函数模板,以便一个匹配任意迭代器,另一个匹配列表迭代器,没有歧义。

请注意,标准中实际上并不能保证list&lt;T&gt;::iteratorsome_other_container&lt;T&gt;::iterator 是不同的类型。因此,尽管在实践中您希望每个容器都有自己的迭代器,但原则上该方法存在很大缺陷,除了您建议将重载放在std 中。您不能单独使用迭代器对其相应的容器进行“结构性”更改。

您可以毫不含糊地做到这一点:

template <typename Container>
void erase_all(Container &, const typename Container::value_type &);

template <typename T>
void erase_all(std::list<T> &, const T &);

【讨论】:

    【解决方案2】:

    list::removelist::erase 单独执行您所看到的擦除/删除习语对向量的作用。

    remove 用于值或谓词。 erase 用于单个迭代器或范围。

    【讨论】:

    • 谢谢,但我确实知道列表成员函数,但它不能回答我的问题。假设我的代码中有很多模板函数使用擦除删除来处理通用容器,我不想为 std::list 重载所有模板函数。
    • 嗨,@antje-m。您可能被误导,认为擦除/删除习惯用法是所有容器的通用方法。它对 大多数 容器类型无效。另外,如果它用于std::list,它会比我链接到的函数慢得多。
    • @antje-m 也许你会从询问“通用容器移除器”而不是询问 如何 来进行擦除/移除正确的方法中受益更多。祝你好运!
    • @DrewDormann:前几天有人问过这个问题。 stackoverflow.com/questions/16013545/…
    【解决方案3】:

    您收到的建议很好,但并不普遍。例如,这对std::vector 很好,但对std::list 完全没有必要,因为std::list::erase()std::list::remove() 已经做了正确的事情。它们会执行您要求的所有指针魔术,std::vector::erase() 无法做到,因为它的内部存储不同。这就是为什么std::remove() 不专门用于std::list 的原因:因为在这种情况下不需要使用它。

    【讨论】:

      猜你喜欢
      • 2018-12-16
      • 1970-01-01
      • 2020-03-19
      • 1970-01-01
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      • 2011-02-08
      • 2021-03-03
      相关资源
      最近更新 更多