添加元素时 OpenMesh 迭代器是否发生变化?

Are OpenMesh iterators changed when adding elements?

当我添加元素时,现有的 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中搜索typedef std::vector<就可以找到。但 add_face 不会重新分配此迭代器,因为新的顶点句柄或面句柄将 push_back 到此向量的末尾。同时,为了拥有高效的搜索速度,Openmesh 至少构建了三层迭代器,我们讨论的向量只是最底层的迭代器。中间或顶部迭代器,我通过 assemble 函数使用它们,所以我不确定它是否是 reallocated/invalidated,你可以在 PolyConnectivity.hhTriConnectivity.hh 中找到它们].

当您添加元素时,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()) {...} 将包含已删除的元素。

垃圾收集

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

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