为什么 std::remove、std::remove_if 与容器有“擦除-删除习惯用法”?

Guy*_*zmo 6 c++ stl

我只是在研究为什么该函数std::remove_if没有按我预期的方式工作,并了解了 C++“擦除删除习惯用法”,我应该将结果传递给removeorremove_iferase实际从容器中删除我想要的项目。

这让我觉得非常不直观:这意味着remove不要remove_if按照他们所说的去做。它还会导致代码更加冗长、不太清晰。

这有道理吗?我认为存在某种权衡,其优点可以平衡我在上一段中列出的缺点。

我的第一个想法是,有一些使用removeremove_if单独使用的用例,但由于它们将集合中的其余项目留在未定义的状态,我想不出任何可能的用例。

Nic*_*las 13

这是容器/迭代器/算法范式工作方式的必要功能。该模型的基本概念如下:

  • 容器包含并管理值序列。
  • 算法作用于值序列。
  • 迭代器表示值序列中的可移动位置。

因此,算法作用于迭代器,迭代器表示通常由容器提供的某些值序列中的位置。

问题是从容器中取出物品不符合这种范式。从容器中删除元素并不是对“值序列”的操作;而是对“值序列”的操作。它从根本上改变了序列本身的性质。

也就是说,“删除”最终以容器操作完成,而不是迭代器操作。如果算法仅作用于迭代器,则没有纯算法可以真正删除元素。迭代器不知道如何做到这一点。仅作用于迭代器的算法可以在序列内移动值,但它们不能改变序列的性质,使得“删除的”值不再存在。

但是,虽然元素的删除是一个容器操作......但它不是一个与值无关的操作。remove仅删除与给定值相等的值。remove_if仅删除谓词返回 true 的值。这些不是集装箱操作;它们是并不真正关心容器性质的算法。

除非需要将它们从容器中实际取出。从上述范式的角度来看,它本质上是两个独立的操作:算法后面是容器操作。

总而言之,C++20 确实提供了许多容器非成员std::erasestd::erase_if特化。它们作为非成员函数完成了擦除-删除的全部工作。

我的第一个想法是,有一些使用removeremove_if单独使用的用例,但由于它们将集合中的其余项目留在未定义的状态,我想不出任何可能的用例。

它有一些用途。多重去除是显而易见的。您可以执行一系列删除操作,只要将新的结束迭代器传递给每个后续删除(以便没有操作检查已删除的元素)。erase最后你可以做一个合适的容器。

还应该注意的是,C++20std::erasestd::erase_if函数仅采用容器,而不采用容器的子部分。也就是说,它们不允许您从容器内的某个范围内进行擦除。只有擦除/删除习惯用法才允许这样做。

此外,并非所有容器都可以删除元素。std::array有固定的尺寸;真正删除元素是不允许的。std::remove但只要您跟踪新的结束迭代器,您仍然可以使用它们。


hev*_*ev1 7

标准库中的许多算法都在通用迭代器上运行,不能用于删除元素。erase是容器的一个方法,可以访问更多的信息,所以可以用来直接删除元素。