如何为std::list重载std::remove

How to overload std::remove for std::list?

本文关键字:std 重载 remove list      更新时间:2023-10-16

我曾经了解到,从容器中擦除元素的一般方法是通过擦除-移除习惯用法。但我惊讶地发现,至少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);

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

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

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<T>::iteratorsome_other_container<T>::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 &);

list::removelist::erase单独使用将完成您所看到的擦除/移除习惯用法对向量所做的操作。

值或谓词的removeerase用于单个迭代器或范围。

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