是否可以滥用谓词在删除元素之前对元素执行操作remove_if?

Can I abuse a predicate to perform operations on the elements before remove_if removes them?

提问人:sbi 提问时间:1/8/2017 最后编辑:sbi 更新时间:1/8/2017 访问量:258

问:

我有一个对象的std::list。列表是排序的,必须保持这种状态。我需要找到那些满足特定条件的对象(我有一个谓词),将它们传递给函数,然后从列表中删除这些对象。

编写一个循环并不难,该循环调用 ,调用其结果(如果有),调用 ,并将结果作为开始迭代器传递给 的下一个调用。然而,IME 人们发现这样的代码比编写更难阅读。std::find_if()list.erase()std::find_if()

因此,我最好使用std库中的一些算法,而不是编写自己的循环。

一个想法是(ab)use : 在返回之前对_from谓词匹配的元素调用操作,以便列表将删除这些元素。这是否符合标准?(项目本身不会更改,只会更改它们引用的数据。std::list<>::remove_if()true

或者你能想出更好的解决方案吗?(同样,主要目的是使它易于阅读和理解。也许是因为我刚刚遇到了它,但对我来说,这似乎是一系列对象的常见使用模式。

注意:目前,我们牢牢地停留在C++03的领域。 C++ 11/14/17 解决方案会很有趣,因此很受欢迎,但我确实需要一些适用于 C++03 的东西。:-/

++ 算法 C++03

评论

0赞 skypjack 1/8/2017
您可以在执行过程中将迭代器存储在某个地方并在最后删除这些元素吗?for_each
0赞 sbi 1/8/2017
@skypjack:我也想到了这一点。不过,它看起来笨拙而繁琐,并且需要两次通过列表。(请注意,该列表受互斥锁保护,互斥锁会阻止其他操作。
0赞 skypjack 1/8/2017
一次遍历列表,一次遍历迭代器(可能是几个)。无论如何,我明白你的意思,但我发现在理想情况下仅用于检查条件的一元谓词中执行操作的想法有点棘手。
0赞 sbi 1/8/2017
@skypjack:您忘记了通过列表来擦除找到的对象。还是我错过了什么?而且,是的,我也觉得这很棘手。这就是我来这里的原因。
0赞 skypjack 1/8/2017
如果你有迭代器,则不必跳过列表来擦除它们。它具有恒定的复杂性。此外,擦除迭代器不会使其他迭代器失效。我们说的是,对吧?std::list

答:

5赞 Barry 1/8/2017 #1

是否可以滥用谓词在删除元素之前对元素执行操作?remove_if

是的。标准规范中没有任何内容要求谓词是纯函数。所以这个 C++11 解决方案是完全可以的:

my_list.remove_if([f, pred](Elem const& e){
    if (pred(e)) {
        f(e);
        return true;
    }
    return false;
});

甚至没有任何东西要求谓词返回。你甚至可以像穷人一样,不必要地混淆:trueremove_iffor_each

my_list.remove_if([f](Elem const& e){
    f(e);
    return false;
});

这是毫无意义和低效的,但它绝对符合标准。

可以在 C++03 中将等效项编写为函数对象。你是否觉得它比for循环更容易阅读是一个见仁见智的问题。但这并没有错。

评论

1赞 user2864740 1/8/2017
我几乎不认为滥用预期的 API 和一般期望“没有错”。否则,代码最终会有很多小宝石。它可能不违反规范;就这样吧。
0赞 sbi 1/10/2017
最后,我选择了 ,它很好地将我正在寻找的项目放在列表的两端,我可以在其中处理和删除它们。尽管如此,这确实回答了我最初的问题,所以它得到了我的帮助。std::stable_partition