将STL容器与迭代器一起使用的常见误用是什么?
9 回答
如果您通过插入或删除容器成员来更改容器,请忘记迭代器通常会失效。
对于使用 STL 的许多重要提示,我强烈推荐 Scott Meyers 的书“Effective STL”(经过消毒的亚马逊链接)
结束范围检查应该使用 != 而不是 < 因为不能保证指针的顺序。
例子:
for(it = list.begin(); it != list.end(); ++it)
{
// do stuff
}
可以在预增量时进行后增量。
其他几个:
将反向迭代器转换为基迭代器,而无需记住迭代器现在将是它所指向的元素之外的一个元素。
尝试使用需要随机访问迭代器和集合和映射等迭代器的算法。
使用非常量迭代器编辑映射条目的键(这恰好构建在 VS.Net 上,但不会使用 GCC)
在不阅读 Scott Meyers 的“Effective STL”书的情况下使用它们。:) 真的。这使得大多数愚蠢的错误消失了。
之后适当的继续erase()
。
假设:
Container::iterator i = cont.begin(), iEnd = cont.end();
例如std::map
,这不是一个好主意:
for (; i != iEnd; ++i) {
if (i->second.eraseCondition()) {
cont.erase(i);
}
}
这会起作用:
for (; i != iEnd; ) {
Container::iterator temp = i;
++temp;
if (i->second.eraseCondition()) {
cont.erase(i);
}
i = temp;
}
这也是:
for (; i != iEnd; ) {
if (i->second.eraseCondition()) {
cont.erase(i++);
}
else {
++i;
}
}
真的太多次了,我不得不在一些生产代码中应用这些修复:(
在容器内使用 auto_ptr,例如
list<auto_ptr<int> > foo;
幸运的是,现在编写了很多 auto_ptr 实现来使这成为不可能。
这不仅是 STL 容器的问题——在迭代容器时修改容器几乎总是会导致问题。
这是游戏中非常常见的错误来源——大多数游戏循环包括迭代每个游戏对象做某事。如果这个东西从游戏对象容器中添加或删除元素,几乎肯定有错误。
解决方案 - 有两个容器 - objectsToDelete 和 objectsToAdd - 在游戏代码中将对象添加到该容器,并仅在您迭代后更新游戏对象容器。
可以设置 objetsToAdd 以确保我们不会多次删除任何内容。
如果您可以构造 Object 而不将其添加到游戏对象容器中,则 objectsToDelete 可以是 Queue,或者如果您的代码假定 Object 实例总是在创建后直接添加到游戏对象容器中(例如在构造函数中),它可以是其他一些类(ObjectCreateCommand?) )。
list<int> l1, l2;
// ...
for_each(l1.begin(), l2.end(), do_it());