首页 > 解决方案 > 即使谓词返回 false,remove_if 也会删除元素?

问题描述

我正在写一个八叉树算法。在函数内部我遍历八叉树。我得到节点指针和球体作为输入。我检查节点是否应该保持球体然后我想将它添加到节点s object list and remove it from its parent的列表中。以下是代码

functionBody()
{
 .....

  if (!node->objectList.empty())
      node->objectList.erase(std::remove_if(node->objectList.begin(), node->objectList.end()-1 , [&t](auto& temp) { return temp == t; }));

...
}

typedef struct Sphere
{
    Sphere() = default;
    Sphere(const Vector3 centre_, const float radius_, const Material& material_) : centre(centre_), radius(radius_), material(material_)
    {
        assert(radius != 0);
        invRadius = 1.0 / radius;

        Vector3 radiusOffset = Vector3(radius);
        aabb.min = Vector3(centre - radiusOffset);
        aabb.max = Vector3(centre + radiusOffset);
    }

    bool operator==(const Sphere& rhs)
    {
        return (centre == rhs.centre) && (radius == rhs.radius);
    }

    Vector3 centre;
    float radius;
    float invRadius;
    Material material;
    AABB aabb;

}Sphere;

正如你所看到的,我已经operator==定义了 Sphere。

我看到remove_if即使谓词返回错误,它也会删除元素。

例如,第一次迭代它找到一个球体t并使用remove_if. 这t最后出现在向量中。现在考虑父母在其向量中仍然有3个球体,但是,当我现在去其他孩子时,我们仍然尝试t在父母中搜索并且remove_if仍然删除最后一个条目。我不明白为什么?

标签: c++algorithmvectorc++-standard-libraryerase-remove-idiom

解决方案


std::remove_if返回end没有找到要删除的内容时提供的迭代器。您已经给出node->objectList.end()-1了结束迭代器,它是 . 中最后一个元素的迭代器node->objectList。这是您erase在找不到时传递给t的内容,因此最后一个元素被删除。

要解决此问题,请使用erase需要一系列元素的重载:

if (!node->objectList.empty())
{
    auto end_iter = node->objectList.end();
    auto to_remove = std::remove_if(
        node->objectList.begin(), end_iter, 
        [&t](auto& temp) { return temp == t; });

    node->objectList.erase(to_remove, end_iter);
}

现在 if tis not founderase根本不会做任何事情。在这种情况下,remove_if返回end_itererase尝试擦除由end_iter和自身定义的空范围内的元素。

我不确定你为什么使用node->objectList.end() - 1. 我假设这是一个错误或解决方法,否则您可能会在以前的代码中遇到这种情况。


推荐阅读