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

#include <list>

list<MyClass> things;

class MyClass {
   // some stuff

   void remove() {
       things.remove_if(THING_IS_ME);
   }
};

我需要写什么而不是thing_is_me?

换句话说,我正在使用全局STL列表作为事物的集合。在某个时候,列表中的一个对象认识到它是多余的并且想要a)从列表中删除,b)遭到破坏。

我该怎么做呢?

我已经有15年没有写了C ++,在这里对此页面有些困惑: http://www.cplusplus.com/reference/algorithm/remove_if/

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

有帮助吗?

解决方案

(最初是一组评论,但在发现OP实际想做的事情之后重写为答案。)

您确实意识到STL容器存储 副本 您插入的东西,对吗?这意味着实例 MyClass 最好比较(例如通过 operator==) - 您不能仅比较地址,因为它们始终会有所不同。

如果拥有myclass副本没有意义,那么您可能会更好 指针容器.

话虽如此,默认情况下,C ++语言使用副本。该语言要求您在代码中明确说明参考之类的内容。我强烈建议你接你 一本好的C ++书 或者,将来您会被这样的问题所绊倒。

其他提示

在过去的15年中,C ++的情况发生了巨大变化。 1994年7月,亚历山大·史蒂芬诺夫(Alexander Stepanov)提出的图书馆提议结合了他的通用编程思想,获得了ANSI/ISO委员会的最终批准。我们今天便利地称呼STL随后成为标准的C ++库。 STL的故事与背后的想法一样引人入胜,这绝对值得阅读。

std::remove_if() 您发现的功能只是这种哲学的另一种反映,它成为C ++现代身份的一部分。简而言之,这是一个通用函数,可以在任何元素的容器(序列)以及任何(如a)条件的情况下使用。为此,您必须提供两件事:

  1. 几个 迭代器 划定您希望处理的元素范围;
  2. 谓词 如果要删除该元素,则在元素上调用时,将返回true。

事实证明,在这种情况下,您想要的谓词是平等。而且,由于基于平等删除元素是一项普遍的任务,因此标准还提供了 std::remove() 函数,假设隐式平等谓词。当然,您必须确保元素可以比较:

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

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

std::remove(things.begin(), things.end(), *this);  // if *this == elem

回想一下标准功能 std::remove() 工作 任何 容器,甚至尚未创建的容器。因为每种容器都有自己的删除元素的方式,因此如果不知道其工作的容器的实现细节,此功能就无法真正执行删除。因此,相反, std::remove() 函数交换元素围绕元素,以使“删除”元素在容器的末端。然后,它返回一个迭代器,指向连续元素的第一个元素“删除”。

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

最后,我们通过调用特定容器的删除功能来真正删除元素,该功能在列表中的单个位置或连续元素范围内可删除:

things.erase(first_removed, things.end());

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

things.erase(std::remove(things.begin(), things.end(), *this),
             things.end());

这一切似乎都令人不知所措和复杂,但是它具有一些优势。一方面,标准库的设计支持动态编程。它还允许标准库提供具有非常苗条的接口的容器,以及在许多不同类型的容器上使用的少数免费功能。它使您可以快速创建一个容器,并立即获得标准库的所有功能与之使用。另外,它允许您快速编写一个通用功能,该功能可以立即与所有标准容器一起使用 - 那些已经编写的容器和尚未书写的容器。

首先,一个简单的手写循环:

for( list<MyClass>::iterator it = things.begin(); it != things.end(); /*  */ ) {
    if( qualifiesForDelete( *it ) ) {
        it = things.erase( it );
    }
    else {
        ++it;
    }
}

第二,使用 remove_if 算法。 remove_if 作为算法,而不是 list, ,实际上无法删除任何元素,而是将被删除的元素移至列表的尽头。随后 erase 必须称呼。这是一个非常重要的成语, 擦除示例, ,必须学到。

things.erase( 
    remove_if( things.begin(), things.end(), deletionPredicate ), 
    things.end() 
);

在哪里 deletionPredicate 是一个函数或函数对象,该函数或函数对象采用单个类型的参数并返回 bool. 。元素 true 返回被认为被删除。

remove_if 函数采用三个参数:两个迭代器定义您正在处理的范围和一个谓词(返回的测试功能 bool)。开始迭代器指向您要处理的第一个元素;末端迭代器指向范围内最后一个元素之后的元素。

在示例中 您链接到的页面, ,谓词是代码行

bool IsOdd (int i) { return ((i%2)==1); }

要使您的代码做您想做的事,您需要写这样的东西:

things.remove_if(things.begin(), things.end(), SomePredicateFunction);

您会定义 SomePredicateFunction 像这样(更换 true 进行适当的测试):

bool SomePredicateFunction (MyClass c) { return true; }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top