添加元素时是否更改了 OpenMesh 迭代器? 垃圾收集

问题描述

当我添加元素时,现有的 OpenMesh 迭代器会改变吗?

示例代码

auto vh1 = mesh.vertex_handle(0);
auto vh2 = mesh.vertex_handle(1);
auto vh3 = mesh.vertex_handle(2);
for(auto fh: mesh.faces()) {
    mesh.add_face(vh1,vh2,vh3);
}

我在文档中没有找到相关内容

示例似乎有效,但我想知道它是否是未定义的行为,或者 OpenMesh 是否承诺确保迭代器在循环期间不会改变。

解决方法

当您添加元素时,OpenMesh 不会更改迭代器,但我认为 OpenMesh 不会对此做出承诺。

OpenMesh 迭代器基本上只是整数。 (它们持有一个 SmartHandle 和一些关于哪些元素应该被跳过的信息。一个 SmartHandle 持有一个 Handle 和一个对网格的引用。一个 Handle 只是一个强类型整数。) 递增迭代器只会递增整数(直到达到不应跳过的元素)。由于您始终通过网格和句柄访问元素,因此存储元素的实际内存的重定位不是问题。

请注意,根据您对循环进行编码的方式,新元素可能会或可能不会被迭代。

for (auto it = mesh_.vertices_begin(); it != mesh_.vertices_end(); ++it)
{
  mesh_.add_vertex(point);
}

上面的循环将包括新添加的顶点,因为 mesh_.vertices_end() 会为每次比较重新评估,因此将包括新添加的元素。在这种情况下,这会导致无限循环。

auto end = mesh_.vertices.end();
for (auto it = mesh_.vertices_begin(); it != end; ++it)
{
  mesh_.add_vertex(point);
}

在这种情况下,新添加的元素将不会包含在循环中。这是因为 end 在开始时只计算一次,并且基本上只保存网格在那个点的顶点数。

for (auto vh : mesh_.vertices())
{
  mesh_.add_vertex(point);
}

这也将作为第二个版本,vertices_end() 只在开始时评估一次。

删除

因为它是在另一个答案中提出的,所以我想快速谈谈删除。 删除元素只会将其标记为已删除。因此,在迭代元素时删除元素是可以的。

当您删除尚未访问过的元素时,它们以后可能会也可能不会被迭代。如果使用跳过迭代器,删除的元素将被跳过,否则不会被跳过。

对于 OpenMesh 7.0 或更新版本,for (auto fh : mesh_.faces()) {...}包含已删除的元素。

相反,for (auto fh : mesh_.all_faces()) {...} 将包含已删除的元素。

垃圾收集

您可能不应该在循环中调用垃圾回收。如果删除了元素,垃圾回收会导致两个问题。首先,它减小了存储元素的容器的大小。因此,评估结束迭代器一次的循环版本可能会运行得太远而崩溃。

如果您使用其他版本的循环或设法创建的新元素多于删除的元素,您仍然会遇到垃圾回收会将元素从后面移动到标记为已删除的元素的位置的问题。因此,如果将这些元素移动到您已经通过的位置,您就会错过这些元素。

,

可以在openmesh中搜索typedef std::vector<,然后就可以找到了。但 add_face 不会重新分配这个迭代器,因为新的顶点句柄或面句柄会 push_back 到这个向量的末尾。同时,为了获得高效的搜索速度,Openmesh 至少构建了三层迭代器,我们讨论的向量只是其中的最底层。中间或顶部迭代器,我通过汇编函数使用它们,所以我不确定它是否会被重新分配/失效,您可以在 PolyConnectivity.hhTriConnectivity.hh 中找到它们。