为什么C++有“擦除-移除习惯用法”?

pqwbnv8z  于 2022-12-20  发布在  其他
关注(0)|答案(2)|浏览(132)

我只是在研究函数std::remove_if为什么不能按我预期的方式工作,并了解了C++的“擦除-删除习惯用法”,即我应该将removeremove_if的结果传递给erase,以实际从容器中删除我想要的项。
这让我觉得很不直观:这意味着removeremove_if不执行它们在tin上说的话。这也会导致代码更冗长,更不清晰。
这有什么正当理由吗?我认为这是一种权衡,我在前一段中列出的好处与坏处是平衡的。
我的第一个想法是,有一些单独使用removeremove_if的用例,但由于它们将集合中的剩余项保留在未定义状态,因此我想不出任何可能的用例。

wpx232ag

wpx232ag1#

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

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

因此,算法作用于迭代器,迭代器表示某个值序列中的位置,通常由容器提供。
问题是从容器中移除一个项目并不符合这个范例,从容器中移除一个元素并不是对一个“值序列”的操作;它从根本上“改变”了序列本身的性质。
也就是说,“移除”最终以一个 * 容器操作 * 而不是迭代器操作结束。如果算法只作用于迭代器,那么没有一个纯粹的算法能够真正地“移除”元素。迭代器不知道如何做到这一点。只作用于迭代器的算法可以在序列中移动值,但它们不能改变序列的性质,从而使“移除”的值不再存在。
但是,虽然删除元素是一个容器操作...它不是一个值 * 不可知 * 操作。remove只删除比较等于给定值的值。remove_if只删除 predicate 返回true的值。这些不是容器操作;它们是“算法”,并不真正关心容器的性质。
除了实际从容器中移除它们的时候,从上面范例的Angular 来看,它本质上是两个独立的操作:一个算法,后面跟着一个容器操作。
尽管如此,C20还是给予a number of containers non-member std::erase and std::erase_if specializations,它们作为一个非成员函数完成了擦除的全部工作。
我的第一个想法是,有一些单独使用removeremove_if的用例,但由于它们将集合中的剩余项保留在未定义状态,因此我想不出任何可能的用例。
它有很多用途,多次移除是显而易见的,你可以执行一系列移除操作,只要你把新的结束迭代器传递给每一个后续的移除操作(这样就没有操作检查被移除的元素),你可以在最后做一个合适的容器erase
需要注意的是,C
20 std::erasestd::erase_if函数只接受容器,而不接受容器的 * sub-section *,也就是说,它们不允许你擦除容器中的某个区域,只有erase/remove习惯用法允许这样做。
此外,并非所有容器都可以擦除元素。std::array具有固定大小;真正的擦除元素是不允许的,但是你仍然可以使用std::remove,只要你跟踪新的结束迭代器。

cclgggtu

cclgggtu2#

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

相关问题