在C++中,从列表中删除对象

int*_*tar 1 c++ stl remove-if

我正在写一个或多或少像这样的程序:

#include <list>

list<MyClass> things;

class MyClass {
   // some stuff

   void remove() {
       things.remove_if(THING_IS_ME);
   }
};
Run Code Online (Sandbox Code Playgroud)

我需要写什么而不是THING_IS_ME?

换句话说,我使用全局STL列表作为事物的集合.在某些时候,列表中的对象识别出它是多余的并且想要a)将自己从列表中移除,并且b)使自己被破坏.

我该怎么做呢?

我已经写了大约15年的C++并且在这个页面上有点困惑:http://www.cplusplus.com/reference/algorithm/remove_if/

这些谓词是什么?C++现在有更高阶的功能吗?

wil*_*ell 5

在过去的15年中,C++的情况发生了巨大变化.1994年7月,亚历山大·斯捷潘诺夫(Alexander Stepanov)提出的关于通用编程理念的图书馆的提议获得了ANSI/ISO委员会的最终批准.我们今天方便地称之为STL的库随后成为标准C++库.STL的故事与它背后的想法一样迷人,它绝对值得一读.

std::remove_if()你发现的功能只是这种哲学的另一种反映,它成为了C++现代身份的一部分.简而言之,这是一个通用函数,可以处理任何元素的容器(序列)和任何(表现为a)的条件.为此,您必须提供两个功能:

  1. 一些迭代器,用于界定您希望处理的元素范围;
  2. 和一个谓词,当在一个元素上调用时,如果要删除该元素则返回true,否则返回false.

事实证明,在这种情况下,您想要的谓词是相等的谓词.并且因为基于相等性去除元素是如此常见的任务,所以标准还提供了std::remove()假定隐式等式谓词的函数.当然,您必须确保元素可以比较:

bool operator==(const MyClass& a, const MyClass& b)
{
    // return true if the two are equal, and false otherwise.
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用我们的谓词来删除类型的元素MyClass:

std::remove(things.begin(), things.end(), *this);  // if *this == elem
Run Code Online (Sandbox Code Playgroud)

回想一下,标准函数std::remove()适用于任何容器,甚至是尚未创建的容器.因为每种容器都有自己的删除元素的方法,所以如果不知道它所使用的容器的实现细节,这个函数就无法真正执行删除.因此,该std::remove()函数交换元素,使得"移除"元素位于容器的末尾.然后,它返回一个迭代器,指向连续元素"removed"的第一个元素.

typedef std::list<MyClass>::iterator iter;
iter first_removed = std::remove(things.begin(), things.end(), *this);
Run Code Online (Sandbox Code Playgroud)

最后,我们通过调用特定容器的删除功能来真正删除元素,该功能适用​​于列表中的单个位置或要删除的一系列连续元素:

things.erase(first_removed, things.end());
Run Code Online (Sandbox Code Playgroud)

在一行中看到这种代码并不罕见:

things.erase(std::remove(things.begin(), things.end(), *this),
             things.end());
Run Code Online (Sandbox Code Playgroud)

这一切看起来都是压倒性的和复杂的,但它有一些优点.首先,标准库的这种设计支持动态编程.它还允许标准库提供具有非常纤薄的接口的容器,以及几种可用于许多不同类型容器的自由功能.它允许您快速创建容器并立即获得标准库的所有功能以使用它.或者,它允许您快速编写一个通用函数,该函数可立即与所有标准容器一起使用 - 已经写好的那些容器和那些尚未写入的容器.