Do existing OpenMesh iterators change, when I add elements?
Example code:
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);
}
I did not find something about this in the documentation.
Example seem to work, but I want to know if it's undefined behavior or if OpenMesh promises to make sure that the iterator does not change during the loop.
OpenMesh does not change the iterators when you add elements, but I don't think OpenMesh gives you a promise on that.
OpenMesh iterators are basically just ints. (They hold a SmartHandle and some information about which elements should be skipped. A SmartHandle holds a Handle and a reference to the mesh. A Handle is just a strongly typed integer.) Incrementing the iterator will just increment the integer (until an element is reached which should not be skipped). Since you always access elements via the mesh and a handle the relocation of the actual memory that stores the elements is not a problem.
Note that depending on how you code your loop the new element may or may not be iterated over.
for (auto it = mesh_.vertices_begin(); it != mesh_.vertices_end(); ++it)
{
mesh_.add_vertex(point);
}
The loop above will include the newly added vertex as mesh_.vertices_end()
is reevaluated for each comparison and will thus include the newly added elements. This leads to an infinite loop in that case.
auto end = mesh_.vertices.end();
for (auto it = mesh_.vertices_begin(); it != end; ++it)
{
mesh_.add_vertex(point);
}
In this case, the newly added elements will not be contained in the loop. That is because end is evaluated only once in the beginning and basically just holds the number of vertices the mesh had at that point.
for (auto vh : mesh_.vertices())
{
mesh_.add_vertex(point);
}
This will behave as the second version as here, too, vertices_end()
is only evaluated once in the beginning.
Since it was brought up in the other answer I want to quickly talk about deletion. Deleting an element will only mark it as deleted. Thus, deleting elements while iterating over the elements is fine.
When you delete elements which have not been visited yet, they may or may not be iterated over later. If you use skipping iterators the deleted elements will be skipped, otherwise they won't be skipped.
For OpenMesh 7.0 or newer for (auto fh : mesh_.faces()) {...}
will not include deleted elements.
Instead for (auto fh : mesh_.all_faces()) {...}
will include deleted elements.
You should probably not call garbage collection inside your loop. If you have deleted elements, garbage collection will cause two problems. First, it reduces the size of the container storing the elements. Thus, versions of the loop that evaluate the end iterator once will likely run too far and crash.
If you use the other version of the loop or manage to create more new elements than you remove, you still have the problem that garbage collection will move elements from the back into the spots of the elements that were marked as deleted. Thus, you will miss those elements if they are moved to spots that you already passed.