for循环中的向量擦除功能无法正确擦除类的向量 [英] Vector erase function in for loop is not erasing vector of classes properly
问题描述
我有一个简单的for循环:
I have a simple for loop:
for (int i = 0; i < c.numparticles; i++)
{
if ( labs((noncollision[i].getypos())) > 5000 )
{
noncollision.erase (noncollision.begin()+i);
}
}
其中非冲突
是 particle
类的向量。在此特定示例中,应删除任何 ypos
大于<5000的 noncollision
。我一直在使用大小为6的 noncollision
,其中2个 ypos
远大于5000。但是,这for循环仅擦除其中一个,而完全忽略另一个。我的怀疑是,因为 noncollision
是类的向量,所以这些类在某种程度上受到了保护,或者导致数组函数的行为不同?这是我对非碰撞
和粒子
的声明:
Where noncollision
is a vector of class particle
. In this specific example, any noncollision
which has a ypos
greater than 5000 should be erased. I have been working with a noncollision
size of 6, of which 2 have ypos
much greater than 5000. However, this for loop is only erasing one of them, completely ignoring the other. My suspicion is that because noncollision
is a vector of classes, that this classes is somehow protected, or causes the array function to act differently? Here is my declaration for noncollision
, and for particle
:
vector<particle> noncollision;
class particle{
private:
int xpos;
int ypos;
int xvel;
int yvel;
bool jc; // Has the particle just collided?
public:
etc....
};
有人可以解释为什么会这样,以及如何纠正它?我是否需要为粒子
类设置一个擦除功能?
Could anyone explain why this is happening, and how to rectify it? Do I somehow need to set up an 'erase function' for the particle
class?
推荐答案
如果两个候选元素彼此相邻(例如, i = 5
和 i = 6
),那么您跳过第二个,因为您只是删除了 i = 5
的一个...,那么第二个就变成了 new i = 5
,但您增加 i
可获得 i = 6
在下一个循环中。
If you have two candidate elements next to each other (say, at i=5
and i=6
), then you jump over the second, because you just erased the one at i=5
... then the second becomes the new i=5
but you increment i
to get i=6
on the next loop.
您需要修复循环以正确支持从同一容器中同时删除元素的事实
You need to fix your loop to properly support the fact that you're simultaneously removing elements from the same container over which you're iterating.
通常,您会使用实际的迭代器(而不是计数器 i
),和 vector :: erase
方便地返回一个新的迭代器供您在下一次迭代中使用:
Typically you'd use actual iterators (rather than a counter i
), and vector::erase
conveniently returns a new iterator for you to use in the next iteration:
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++;
}
}
但是,引用Joe Z:
However, quoting Joe Z:
此外,由于
擦除
的向量大小可以是O(N),因此您可以( a)也使用反向迭代器对循环进行基准测试,(b)考虑将未擦除的元素复制到新的向量中,而不是从中间删除元素,或者(c)使用list<
而不是vector<>
(如果从中间删除是常见的操作)。
Also, since
erase
can be O(N) in the size of a vector, you might (a) benchmark the loop using reverse iterators too, (b) consider copying the not-erased elements into a fresh vector as opposed to deleting elements out of the middle, or (c) using alist<>
instead of avector<>
if deleting from the middle is a common operation.
或者,如果您很懒,也可以颠倒您的迭代顺序,以保持计数器 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
具有明智的类型),因为如果这样做,循环将永远不会结束!
Just be careful never to change i
to an unsigned variable (and your compiler is probably warning you to do just that — i.e. to use size_t
instead — if c.numparticles
has a sensible type) because if you do, your loop will never end!
这篇关于for循环中的向量擦除功能无法正确擦除类的向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!