【发布时间】:2019-01-29 14:47:41
【问题描述】:
我有this C++ code file 这是FOSS 根据外籍人士许可证。运行时cppcheck 在代码上我得到这个错误:
[google_hash.cpp:137] -> [google_hash.cpp:141]: (error) Iterator 'it' used after element has been erased.
有问题的代码是:
74 #if (FCS_WHICH_STATES_GOOGLE_HASH == FCS_WHICH_STATES_GOOGLE_HASH__SPARSE)
75 typedef sparse_hash_set<char *, state_hash, state_equality> StatesGoogleHash;
76 #else
77 typedef dense_hash_set<char *, state_hash, state_equality> StatesGoogleHash;
78 #endif
.
.
.
131 extern void fc_solve_states_google_hash_foreach(
132 fcs_states_google_hash_handle void_hash,
133 bool (*should_delete_ptr)(void *key, void *context), void *context)
134 {
135 StatesGoogleHash *hash = (StatesGoogleHash *)void_hash;
136
137 for (StatesGoogleHash::iterator it = hash->begin(); it != hash->end(); ++it)
138 {
139 if (should_delete_ptr(*(it), context))
140 {
141 hash->erase(it);
142 }
143 }
144 }
它利用了 http://goog-sparsehash.sourceforge.net/doc/sparse_hash_set.html 或http://goog-sparsehash.sourceforge.net/doc/dense_hash_set.html。
现在,这些文件说
Validity of Iterators
insert() invalidates all iterators, as does resize().
erase() is guaranteed not to invalidate any iterators.
所以我的问题是 - 我是否正确且安全地使用集合的迭代器 (并且 cppcheck 发出了误报),或者如果不是 - 应该如何 代码是固定的?
我们将不胜感激。
【问题讨论】:
-
根据文档,您似乎是。
it是hash上的迭代器,而hash->erase(it);据说不会使迭代器失效,因此不应使it失效。尽管文档可能不正确,这意味着对其他元素的迭代器无效。或者也许有一种期望,暗示it不算作“任何迭代器”的一部分。请注意,erase标有注释 6,该注释似乎从文档中丢失,可能是为了涵盖这一点。 -
即使
erase()不会使it失效,在你删除它的元素之后it++的用途还不清楚。它绝对不是容器元素的迭代器,那么它代表什么?它是否隐式引用it之后的元素?之前的那个?无论哪种情况,我都认为说它没有失效是不正确的。它当然不能仍然指同一件事。如果它根本不引用特定元素,那么它支持哪些操作?这样的迭代器确实需要它自己的类别定义。 -
对于自称为容器的东西来说,这是一个奇怪的接口。我希望
erase(iterator)函数返回下一个迭代器,而不是void。 -
@FrançoisAndrieux 有一个不能取消引用的 one 迭代器值是很正常的,
end迭代器。似乎这个 api 可以有多个有效但不可取消引用的值。 -
@Caleth 这是一个很好的观点。但它是一个范围内唯一不能取消引用的迭代器值,并且假设用户可以理解过去的迭代器的概念,因为它类似于过去的结束的标准概念指针。
begin和end的特殊之处还在于它们定义了一个范围。同样,假设开发人员会理解对它们的限制是相对安全的,因为如果用户理解迭代器,他们就必须理解范围。这个有效的非end但不可引用的迭代器没有标准的先例并且需要文档。
标签: c++ sparsehash