我有一个循环的简单:
for (int i = 0; i < c.numparticles; i++)
{
if ( labs((noncollision[i].getypos())) > 5000 )
{
noncollision.erase (noncollision.begin()+i);
}
}
其中noncollision
是类的一个矢量particle
。 在这个具体的例子中,任何noncollision
具有ypos
大于5000应被擦除。 我一直与一个noncollision
的6大小,其中2 ypos
比5000然而,这对循环只擦除其中的一个,完全无视其他大得多。 我怀疑是因为noncollision
是类的载体,这个班以某种方式保护,或导致阵列功能,采取不同的行动? 这里是我的声明noncollision
,和particle
:
vector<particle> noncollision;
class particle{
private:
int xpos;
int ypos;
int xvel;
int yvel;
bool jc; // Has the particle just collided?
public:
etc....
};
任何人都可以解释为什么发生这种情况,以及如何纠正呢? 难道我莫名其妙地需要建立一个“擦除功能”为particle
类?
如果你有两个候选元素彼此相邻(比如,在i=5
和i=6
),那么你跳过第二个,因为你只是删除在一个i=5
......那么第二个变成新的 i=5
,但你增加i
得到i=6
上的下一个循环。
你需要修复你的循环正常支持的事实,你同时去除你遍历这同一个容器中的元素。
通常,你会用实际的迭代器(而非计数器i
),以及vector::erase
方便地返回一个新的迭代器,为您的下一次迭代:
vector<particle>::iterator it = noncollision.begin(), end = noncollision.end();
for ( ; it != end; ) { // NB. no `++it` here!
if (labs(it->getypos()) > 5000) {
// erase this element, and get an iterator to the new next one
it = noncollision.erase(it);
// the end's moved, too!
end = noncollision.end();
}
else {
// otherwise, and only otherwise, continue iterating as normal
it++;
}
}
然而,引述乔Z:
另外,由于erase
可以以向量的大小是O(N),则可能的(a)的基准使用反向迭代也(b)考虑复制未擦除的元件到一个新的载体,而不是删除元素圈外的中间,或使用(c)中list<>
代替vector<>
如果从中间删除是一种常见的操作。
或者,如果你懒,你也只是扭转你的迭代顺序,它保留您的计数器的神圣i
在这种特殊情况下:
for (int i = c.numparticles-1; i >= 0; i--) {
if (labs(noncollision[i].getypos()) > 5000) {
noncollision.erase(noncollision.begin()+i);
}
}
只是要小心,从来没有改变i
为无符号变量(和你的编译器可能是警告你要做到这一点-即使用size_t
而不是-如果c.numparticles
有一个合理的类型),因为如果你这样做,你的循环将永远不会结束!
然而,这对循环只擦除其中的一个,完全忽视了其他。
这是因为你要从前到后。 当你的代码删除在,比如,指数6项,这是以前在指数7项是该指数在6现在。 然而,环路将跳过索引6之后i++
,以为这样就已经处理了。
如果你去背到前面,这个问题将是固定的:
for (int i = c.numparticles-1; i >= 0; i--)
{
if ( labs((noncollision[i].getypos())) > 5000 )
{
noncollision.erase (noncollision.begin()+i);
}
}
它看起来像你从“已失效迭代器”综合症,尽管在这种情况下,它这就是问题的指标。
你接下来要对方抹去的2个元素?
的问题是,擦除从一个向量的元素导致其余底层元素被复制到一个新的位置(除非擦除最后一个元素),和减少一个在矢量元素的数量。
由于您使用的索引到载体中,你不落下的第一个问题(这是被无效迭代器)的犯规,但是:
- 你只是删除一前一后立即你将永远不会检查元素
- 你的索引将波及关闭矢量(未定义行为)的结束
修改你在同一回路检查任何序列是一个坏主意。 看一看的remove_if一种更好的方式。 这种算法中把所有匹配的元素在向量的末尾,并返回一个迭代器已移动的第一个,让您安全地删除它们都一气呵成。
文章来源: Vector erase function in for loop is not erasing vector of classes properly