for循环中的向量擦除功能无法正确擦除类的向量 [英] Vector erase function in for loop is not erasing vector of classes properly

查看:134
本文介绍了for循环中的向量擦除功能无法正确擦除类的向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的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 a list<> instead of a vector<> 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆