首页 > 解决方案 > 添加元素时是否更改了 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 会给您一个承诺。

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

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

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()) {...}将包括已删除的元素。

垃圾收集

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

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


推荐阅读