我正在使用较旧的C(使用clang ++进行编译)代码库,该代码库使用一些全局变量来存储链表的头部,整个代码中的许多点遍历这些列表。
struct global_st *global_list; // awful global
// ... somewhere down in the code
for (struct global_st *it = global_list; it; it = it->next)
operation(it);
在某些时候,一些天才发现operation()可能导致从列表中删除项目,尤其是(但不限于)当前的迭代对象。所以有些循环看起来更像是这样:
for (struct global_st *it = global_list, *next_it; it; it = next_it) {
next_it = it->next;
operation_that_could_remove_object(it);
}
但是,许多不太安全的循环使用另一种方法,特别是如果使用相对“安全”的操作(此代码库几乎完全缺乏const)。我已经找到了一些错误,这些错误通过使用对象池来为已分配的结构进行屏蔽,这些结构永远不会清除它们的下一个指针。
我的任务是将此链表更改为std :: vector或std :: list。来自this question,这是7岁,但我认为仍然是真的,我无法检查迭代器是否仍然有效解除引用。 假设迭代的当前对象是可以通过循环中的操作删除的唯一元素,这个循环会被认为是安全的吗?
for (auto it = global_list.begin(), next_it; it != global_list.end(); it = next_it) {
next_it = it;
next_it++;
operation_that_could_remove_object(*it);
}
如果是这样,是否有更简单的方法(或更安全的数据结构)有助于防止程序员错误?我想使用ranged-for语义,但是当迭代器被删除时,这似乎不可能。
我的替代选择是利用对象池并设置'is_valid'标志,然后将删除推迟到以后的时间。但是,我并不特别希望每个循环都检查对象是否仍然有效。
编辑:为了澄清,容器中填充了对象的唯一指针,可能的删除(通过操作(Obj * obj))将指针与容器的成员匹配。既然它们是唯一的,那么是否存在可以应用于从std :: set中迭代/移除的语义?