C++ 删除并向主循环内的向量添加元素

C++ 删除并向主循环内的向量添加元素,c++,vector,openframeworks,C++,Vector,Openframeworks,我以前搜索过,但没有找到任何答案。我对C++有点陌生,所以希望这个问题不会太傻。 我试图添加和删除向量中的元素,在我的例子中,在所有粒子的大更新或绘图循环中填充粒子。例如,删除一些粒子,因为它们死亡了,但也添加了一些其他粒子,因为一个粒子与对象碰撞,我想显示碰撞点处的小粒子爆发。我在一个演示文件中编写了这个简单的测试代码,以弄清问题的根源 我认为问题在于,由于我删除并添加了粒子,迭代器指针变得无效。删除是有效的,但当我添加几个随机的时,我会得到一个空指针。下面的代码有点冗长,我知道我应该在beg

我以前搜索过,但没有找到任何答案。我对C++有点陌生,所以希望这个问题不会太傻。 我试图添加和删除向量中的元素,在我的例子中,在所有粒子的大更新或绘图循环中填充粒子。例如,删除一些粒子,因为它们死亡了,但也添加了一些其他粒子,因为一个粒子与对象碰撞,我想显示碰撞点处的小粒子爆发。我在一个演示文件中编写了这个简单的测试代码,以弄清问题的根源

我认为问题在于,由于我删除并添加了粒子,迭代器指针变得无效。删除是有效的,但当我添加几个随机的时,我会得到一个空指针。下面的代码有点冗长,我知道我应该在begin()和end()中使用迭代器,但我也遇到了同样的问题,并对代码进行了一些处理,尝试了更多javascript数组样式的循环,因为我更熟悉这一点

void testApp::drawParticles()
{

    int i=0;
    int max = particles.size();
    vector<Particle*>::iterator it = particles.begin();

    while ( i < max ) {

        Particle * p = particles[i];

        if ( ofRandom(1) > .9 ) {
            it = particles.erase(it);
            max = particles.size();
        } else {
            ofSetColor(255, 255, 0);
            ofCircle( p->x, p->y, p->z, 10);

            if ( ofRandom(1) < .1 ) addSomeNewOnes();
            i++;
            it++;
        }
    }


}

void testApp::addSomeNewOnes()
{
    int max = ofRandom(4);

    for ( int i=0; i<max; i++ ) {
        Particle * p = new Particle();
        p->x = ofRandom( -ofGetWidth()/2, ofGetWidth()/2 );
        p->y = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
        p->z = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
        particles.push_back( p );
    }
}
void testApp::drawParticles()
{
int i=0;
int max=particles.size();
向量::迭代器it=particles.begin();
而(i.9){
它=粒子。擦除(它);
max=粒子大小();
}否则{
设置颜色(255,255,0);
(p->x,p->y,p->z,10);
如果随机数(1)<.1)添加一些新的();
i++;
it++;
}
}
}
void testApp::addSomeNewOnes()
{
int max=随机数(4);
for(int i=0;ix=of随机(-of网格宽度()/2,of网格宽度()/2);
p->y=of随机(-of thegetlight()/2,of thegetlight()/2);
p->z=ofRandom(-OFGETHIGHT()/2,OFGETHIGHT()/2);
粒子。推回(p);
}
}

在某些情况下,当基础数据发生更改时,迭代器将失效

你必须打破循环,重新开始

通过将整个drawParticles函数包装在
while(notDone)
循环中,并在修改向量后将notDone设置为true,您应该能够做到这一点


这里还有一个关于规则的SO问题:

每次插入到
向量时,该向量的迭代器都可能无效。您不能这样做:

if ( ofRandom(1) < .1 ) addSomeNewOnes();
it++
if(of随机数(1)<.1)addsomenewone();
它++
因为在调用
addSomeNewOnes()
之后,
无效

您可以使用调用
vector::insert
返回的迭代器,但在您的情况下,这将意味着重新设计代码

无论如何,这是您可能想要做的事情,因为您的代码有点混乱

it = particles.erase(it);
将返回一个迭代器,该迭代器指向被擦除的元素后面的元素的新位置。如果被擦除的元素恰好是最后一个,则它将指向
particles。end()
it++
在“end”上是一个错误

此外,如果:

if ( ofRandom(1) < .1 ) addSomeNewOnes();
if(of随机数(1)<.1)addsomenewone();

计算结果为true,并调用
addSomeNewOnes()
,正如其他人所说,这也将使迭代器无效。

您可以从末尾循环该迭代器,这将允许您删除当前内容(因为您只删除末尾的内容),并添加添加到末尾的新内容:

Vector<Particle*>::iterator it = particles.end();

while (iter != particles.begin()) {

    Particle * p = *iter;

    if ( ofRandom(1) > .9 ) {
        particles.erase(iter);
    } else {
        ofSetColor(255, 255, 0);
        ofCircle( p->x, p->y, p->z, 10);

        if ( ofRandom(1) < .1 ) addSomeNewOnes();
    }
    iter--;
}
Vector::iterator it=particles.end();
while(iter!=particles.begin()){
粒子*p=*iter;
如果(随机数(1)>.9){
粒子擦除(iter);
}否则{
设置颜色(255,255,0);
(p->x,p->y,p->z,10);
如果随机数(1)<.1)添加一些新的();
}
国际热核聚变实验堆;
}

如果您没有添加,根据信息,STL中的迭代器是稳定的,因此您应该能够向前迭代,并且仍然能够获得相同的结果。

您是否在迭代器的位置插入和删除?如果是, 插入并删除有效的返回迭代器,您可以使用 这些,比如:

std::vector<T>::iterator i = v.begin();
while ( i != v.end() ) {
    if ( someCondition ) {
        i = v.erase( i );
    } else {
        ++ i;
    }
}
std::vector::iterator i=v.begin();
而(i!=v.end()){
如果(某些条件){
i=v.擦除(i);
}否则{
++一,;
}
}
是一个或多或少的标准习语

对于随机插入和删除,必须使用索引,这 根据插入或删除的图元数进行更新,以及 插入或删除是在当前文件之前还是之后
位置。

有一种简单的方法可以让它正确工作,而不用担心无效规则:只需为下一次迭代构建一个新的向量

typedef vector<Particle*> ParticleVector;

// modifies the particle vector passed in 
void testApp::drawParticles(ParticleVector &particles)
{
    ParticleVector next;
    next.reserve(particles.size()); // seems like a reasonable guess

    for (auto it = particles.begin(); it != particles.end(); ++it)
    {
        Particle *p = *it;

        if (ofRandom(1) > .9) {
            // don't copy to the next cycle
            delete p;
        } else {
            // copy to the next cycle
            next.push_back(p);

            ofSetColor(255, 255, 0);
            ofCircle(p->x, p->y, p->z, 10);

            if (ofRandom(1) < .1)
                addSomeNewOnesTo(next);
        }
    }
    particles.swap(next);
}
typedef向量ParticleVector;
//修改传入的粒子向量
void testApp::drawParticles(ParticleVector和particles)
{
下一步是ParticleVector;
next.reserve(particles.size());//似乎是一个合理的猜测
for(auto it=particles.begin();it!=particles.end();+it)
{
粒子*p=*it;
如果(随机数(1)>.9){
//不要复制到下一个周期
删除p;
}否则{
//复制到下一个周期
下一步,将_向后推(p);
设置颜色(255,255,0);
(p->x,p->y,p->z,10);
如果(随机数(1)<.1)
添加新的内容到(下一步);
}
}
粒子交换(下一步);
}
请注意,当您不使用globals时,像这样进行重构是多么容易,顺便说一句

void testApp::addSomeNewOnesTo(ParticleVector &particles)
{
    int max = ofRandom(4);

    for ( int i=0; i<max; i++ ) {
        Particle * p = new Particle();
        p->x = ofRandom( -ofGetWidth()/2, ofGetWidth()/2 );
        p->y = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
        p->z = ofRandom( -ofGetHeight()/2, ofGetHeight()/2 );
        particles.push_back( p );
    }
}
void testApp::addSomeNewOnesTo(ParticleVector和particles)
{
int max=随机数(4);
for(int i=0;ix=of随机(-of网格宽度()/2,of网格宽度()/2);
p->y=of随机(-of thegetlight()/2,of thegetlight()/2);
p->z=ofRandom(-OFGETHIGHT()/2,OFGETHIGHT()/2);
粒子。推回(p);
}
}

另一个注意事项:您的实现中没有内存泄漏吗? 您正在使用

vector<Particle*>  particles
矢量粒子
还可以使用
particles.erase()
。 这不会只是删除指向粒子的指针,而不是创建对象吗?

那个会