【问题标题】:Is std::remove_if guaranteed to call predicate in order?std::remove_if 是否保证按顺序调用谓词?
【发布时间】:2016-12-14 20:15:06
【问题描述】:

std::remove_if 是否总是按顺序调用每个元素上的谓词(根据迭代器的顺序)还是可以乱序调用?

这是我想做的一个玩具示例:

void processVector(std::vector<int> values)
{
    values.erase(std::remove_if(values.begin(), values.end(), [](int v)
    {
        if (v % 2 == 0)
        {
            std::cout << v << "\n";
            return true;
        }
        return false;
    }));
}

我需要处理和删除满足特定条件的向量的所有元素,而 erase + remove_if 似乎非常适合。但是,我要做的处理有副作用,我需要确保处理按顺序进行(在玩具示例中,假设我想按照它们在原始向量中出现的顺序打印值)。

假设我的谓词将按顺序在每个项目上调用是否安全?

我认为 C++17 的执行策略会消除这种歧义,但由于 C++17 尚未推出,这显然对我没有帮助。

编辑:另外,这是个好主意吗?或者有没有更好的方法来做到这一点?

【问题讨论】:

  • 明确地说,副作用会改变vector 本身吗?这将使在任何情况下使用的迭代器无效,因此最好先确保这一点。我还要警惕可能影响vector 中的 的任何副作用,因为在执行remove_if 期间,vector 中任何给定项目的确切位置是不保证。
  • 不,副作用不会改变向量。副作用实际上是将一些东西写入文件。
  • 我认为天气与否没有实际意义。做所有的副作用,然后做删除。
  • 不,没有这样的保证。
  • 答:使处理没有副作用。分开做。

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


【解决方案1】:

标准不保证调用谓词的顺序。

你应该使用的是stable_partition。您根据谓词对序列进行分区。然后你可以遍历分区序列来执行你想做的任何“副作用”,因为stable_partition 确保了两组数据的相对顺序。然后你就可以擦除vector中的元素了。

stable_partition 必须在此处使用,因为erase_if 未定义“已擦除”元素的内容。

在代码中:

void processVector(std::vector<int> &values)
{
    auto it = std::stable_partition(begin(values), end(values), [](int v) {return v % 2 != 0;});

    std::for_each(it, end(values), [](int v) {std::cout << v << "\n";});

    values.erase(it, end(values));
}

【讨论】:

  • 是的,我重新阅读了这个问题以仔细检查自己,然后删除了评论。仍然:为什么不简单地做erase_if,然后是for_each
  • @MooingDuck:因为erase_if 不保证它移动任何东西到范围末端的“空”槽。 stable_partition 确实如此。
【解决方案2】:

它们应该按顺序处理,但不是保证

std::remove_if() 将“已移除”的项目移动到容器的末尾,直到调用 erase() 后它们才真正从容器中移除。这两个操作都可能使std::vector 中的现有迭代器失效。

【讨论】:

  • 标准中哪里保证了按序加工?
  • @曹大方:是的。我的错。忘了erase 不保证第二个“分区”中的任何内容,这允许它使用更简单的算法。
  • @NicolBolas:我没有说保证按顺序处理,我说应该按顺序处理(见“可能的实施”在cppreference.com)。但是,该标准确实在第 25.3.8 节中为 remove_if() 说明了这一点:“复杂性:恰好 last - first 应用相应谓词。”因此它不能将项目传递给谓词更多不止一次(就像排序一样)。但我想这并不能阻止算法从后到先工作,而不是从前到后工作,尽管后者更有可能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-11
  • 1970-01-01
  • 1970-01-01
  • 2011-02-08
相关资源
最近更新 更多