我正在编写八叉树算法。内部功能我遍历八叉树。我得到节点指针和Sphere作为输入。我检查节点是否应该容纳球体,然后我要添加它到节点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;
您可以为Sphere看到我定义了operator==
。
即使谓词返回false,我也认为remove_if
正在删除元素。
例如,第一次迭代,它找到一个球体t
,并使用remove_if
将其从父向量中删除。此t
存在于向量的最后。考虑到现在父级在其向量中仍然具有3个球体,但是当我转到另一个孩子时,我们仍然尝试在父级中搜索t
,而remove_if
仍会删除最后一个条目。我不明白为什么?
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);
}
现在,如果未找到t
,则erase
将完全不执行任何操作。在这种情况下,remove_if
返回end_iter
,erase
尝试擦除end_iter
及其本身定义的空白区域中的元素。
我不确定您为什么使用node->objectList.end() - 1
。我假设这是崩溃的一种错误或解决方法,否则您可能会用先前的代码得到此崩溃。
[您正在调用只接受一个迭代器(而不是一个迭代器的范围)的方法擦除,并且使用指定的容器元素范围的第二个迭代器调用算法std::remove_if
,
node->objectList.end()-1
然后,即使在容器中找不到该元素,算法remove_if
也会返回指向容器中有效对象的迭代器node->objectList.end()-1
。该对象将从容器中删除。
这里是一个演示程序,可以重现该问题。
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 3, 5, 7, 9 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
while ( v.size() > 1 )
{
v.erase( std::remove_if( std::begin( v ), std::prev( std::end( v ) ),
[]( const auto &item )
{
return item % 2 == 0;
} ) );
}
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
其输出为
1 3 5 7 9
1
即向量中没有元素是偶数。不过,从向量中删除了除一个元素以外的所有元素。
似乎您错误地指定了范围。应该像一对一样指定]
node->objectList.begin(), node->objectList.end()
或在擦除元素之前,应检查返回的迭代器是否等于node->objectList.end() - 1
(前提是您确实要使用问题中显示的范围)。在这种情况下,不应调用擦除方法。或者您应该指定一个迭代器的擦除范围,例如
if (!node->objectList.empty())
node->objectList.erase(std::remove_if(node->objectList.begin(), node->objectList.end()-1 , [&t](auto& temp) { return temp == t; }).
node->objectList.end()-1);
再次提供,您确实希望使用node->objectList.end()-1
之类的范围的第二个迭代器,而不是node->objectList.end()
。