【问题标题】:For the erase-remove idiom, why is the second parameter necessary which points to the end of the container?对于erase-remove 习惯用法,为什么需要第二个参数指向容器的末尾?
【发布时间】:2019-09-29 03:47:04
【问题描述】:

考虑以下代码(取自cppreference.com,稍作改编):

#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>

int main()
{
    std::string str1 = "     Text with some   spaces";
    str1.erase(std::remove(str1.begin(), str1.end(), ' '), str1.end());
    std::cout << str1 << '\n';

    return 0;
}

为什么erase 的第二个参数是必须的? (在这种情况下,即str1.end()。)

为什么我不能将remove 返回的迭代器提供给erase?为什么我还要告诉它要擦除的容器的最后一个元素?

这里的陷阱是你也可以在没有第二个参数的情况下调用erase,但这显然会产生错误的结果。

是否存在我不想将容器末尾作为第二个参数传递给 erase 的用例?

对于擦除删除习语省略erase 的第二个参数是否总是一个错误,或者这可能是一个有效的做法吗?

【问题讨论】:

  • erase 采用开始和结束迭代器。 remove 将要删除的项目打乱(某种)到末尾,并返回一个“新结尾”迭代器——它作为要擦除的范围的开始传递给 erase 函数。您可以创建一个辅助函数,在一次函数调用中为您执行这两项操作。
  • 请考虑您可能希望erase 的范围与remove 标识的范围不同。
  • 不一次性执行这两个操作的一个原因是,在最终擦除容器的尾端。
  • @Eljay -- re: "在最终擦除容器的尾部之前" -- 分离操作的根本原因是算法适用于序列和序列不必有底层容器。也就是说,很可能没有一个容器的尾部必须被移除。
  • 在许多语言中,容器本身就是您传递给算法的东西。 但不是在 C++ 中。在 C++ 中,算法不知道容器——它们只知道两个迭代器之间的元素序列。大多数情况下,这两个迭代器来自一个容器(必然是同一个容器)。但有时它们并不代表容器。 (任何给定的容器都可以将算法实现为一种方法,然后该方法就知道容器了。)而 that 就是为什么 remove() 会随机播放元素,但不会 删除 他们。它不知道要从中删除它们的容器。

标签: c++ stl erase-remove-idiom


【解决方案1】:

std::remove 返回 一个 迭代器;它是序列的新的结束迭代器。但是当序列由容器管理时,容器的大小并没有改变; std::remove 打乱序列中元素的顺序,但实际上并没有删除任何元素。

要删除容器中不属于您调用的新序列的元素,当然是container.erase()。但目标是删除 所有 额外的元素;只用一个迭代器调用container.erase() 会告诉它删除那个元素。要告诉container.erase() 删除“从这里到结束”的所有内容,您必须告诉它both“这里”在哪里以及结束在哪里。所以这意味着两个迭代器。

如果有帮助,请将“删除/擦除”习语视为两个单独的步骤:

auto new_end = std::remove(str1.begin(), str1.end(), ' ');
str1.erase(new_end, str1.end());

【讨论】:

  • 嗯,我对std::remove 会做什么有一个完全错误的印象。感谢您的澄清!但是,我想知道std::remove 的这种行为是否适用于任何类型的容器。在我看来,它只适用于连续存储元素的容器。我无法想象,这种洗牌行为如何应用于像哈希集这样的容器。
  • @j00hi:std::unordered_set 的问题不在于它不连续地存储其元素,而是“移动”一个元素是没有意义的:元素通过它们的哈希值而不是它们的位置来区分. (相比之下,std::list 也以非连续方式存储元素,与 std::remove 一起工作得很好。)并非巧合的是,std::unordered_set&lt;...&gt;::iterator 实际上是一个 constant 迭代器类型,所以它不满足std::remove 的要求——你的编译器应该拒绝像 std::remove(hash_set.begin(), hash_set.end(), ' ') 这样的东西。
猜你喜欢
  • 2010-12-13
  • 2013-07-08
  • 2011-11-19
  • 1970-01-01
  • 2010-11-30
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
  • 1970-01-01
相关资源
最近更新 更多