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

时间:2013-04-17 14:42:27

标签: c++ templates stl

我曾经了解到从容器中擦除元素的一般方法是通过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 ++中的模板/类型特征/过载规则。

3 个答案:

答案 0 :(得分:2)

它没有强制要求,因为它不仅仅是一个优化,它与您对Sequence容器的期望有不同的语义:

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 &);

答案 1 :(得分:1)

单独

list::removelist::erase将执行您已经看到的删除/删除习惯用于向量的内容。

remove表示值或谓词。单个迭代器或范围的erase

答案 2 :(得分:0)

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