Vector array question

Hi guys,

I’m trying to learn a bit more about vector arrays in c++ while creating a simple particle system and am running into an error during compiling.

I’m sure it’s the lack of C++ knowledge on my part is what’s causing the problem, so be gentle :slight_smile:

The code actually compiled once, I’m not sure why, but any time I try to do it now it just crashes.

ofApp.h:

ParticleController mParticleController;

ofApp.cpp
setup:

mParticleController.addParticles( 10 );

update:

mParticleController.update();

draw:

    mParticleController.draw();

Particle.h

#pragma once
#include "ofMain.h"

class Particle {
public:

Particle();
Particle(ofVec2f _l);

ofVec2f loc;
ofVec2f vel;
ofVec2f acc;

void update();
void display();
bool isDead();

float lifespan = 255;
};

Particle.cpp

#include "Particle.h"
Particle::Particle() { }

Particle::Particle(ofVec2f _l) {
acc.set(0, 0.5);
vel.set(ofRandom(-3.0f, 3.0f), ofRandom(-1.0f, 1.0f));
loc.set(_l);
}

void Particle::update () {
vel += acc;
loc += vel;
lifespan -= 5;
}

void Particle::display (){
ofSetColor(50, 50, 50, lifespan);
ofFill();
ofCircle(loc.x, loc.y, 10);
}

bool Particle::isDead(){
if (lifespan <= 0) {
    return true;
} else {
    return false;
}
}

ParticleController.h

#pragma once
#include "ofMain.h"
#include "Particle.h"

class ParticleController {
public:

ParticleController();

void update();
void draw();

void addParticles( int amt );
void removeParticles( int amt );

std::vector<Particle> mParticles;
};

ParticleController.cpp

#include "ParticleController.h"
using std::vector;

ParticleController::ParticleController() {
//mParticles.resize(WIDTH);
//    for (int i = 0; i < WIDTH; ++i) {
//        mParticles[i].resize(HEIGHT);
//    }
//}
//mParticles.reserve(50);
}

void ParticleController::update() {
for( std::vector<Particle>::iterator p = mParticles.begin(); p != mParticles.end(); ++p ){
    p -> update();
}
}

void ParticleController::draw() {
for( std::vector<Particle>::iterator p = mParticles.begin(); p != mParticles.end(); ++p ){
    p -> display();
}
}

void ParticleController::addParticles( int amt ) {
for( int i=0; i < amt; i++ ) {
    float x = ofRandom( 0, ofGetWindowWidth() );
    float y = ofRandom( 0, ofGetWindowHeight() );
    mParticles.push_back( Particle ( ofVec2f( x, y ) ) );
}
}

void ParticleController::removeParticles( int amt ) {
for( int i=0; i<amt; i++ ) {
    mParticles.pop_back();
}
}

What is the error that the compiler gives you?

ok, so I should have posted a screenshot of the error when it happened, but it was late and I went to bed. Today -> reboot and all seems to work well.

Thanks for the reply though!

alright, so one more c++ noob issue I’m running into is that I want 2 new particles to appear when 1 dies. Simple, right? well… it’s not really working out that great for me :slight_smile:
I’m including the comments to show how I’m understanding how the code works.

I start with this in ofApp setup:

    mParticleController.mParticles.reserve(2);
    mParticleController.addParticles( 1 );

and have calls to mParticleController.update(); in the update method.

void ParticleController::update() {
for( std::vector<Particle>::iterator p = mParticles.begin(); p < mParticles.end(); p++ ){
    p -> update();
    
    if ( p -> isDead() ) {  // do stuff if particle is dead
        mParticles.erase(p);
        int addtwo = 2;
        if ( mParticles.size() + addtwo > mParticles.capacity() ) { // if +2 new particles are more than the capacity, then resize to double the capacity
            mParticles.resize(mParticles.capacity()*2);
        } else { // otherwise just add two new particles
            addParticles(addtwo);
        }
    }
}

pink = mParticles.capacity(); // for cout
}

And the error I’m getting is in the image here: http://imgur.com/6Tzdu3p
If I reserve 5000 to start with, and add only 1 particle in the beginning, then limit the addition of particles to a max of 5000, it all works fine. So I assume it’s something with managing memory, but I’m not a 100% sure why my if statements above don’t fully take care of that.

Thanks!

1 Like

I did not studied your problem in details, but you iterate over a vector and you change its content at the same time with the erase() method. Maybe it invalidates the iterator. You should probably dig in that direction.

2 Likes

Can you upload the code so we can test it? Just by looking at it two things that I notice is that when you delete, it returns the latest valid iterator and you are not passing to your existing iterator - more here about how to properly delete elements in a vector.

Also you should increase the iterator after you check if you have deleted elements, not at the beginning of the for loop.

void ParticleController::update() {
 for( std::vector<Particle>::iterator p = mParticles.begin(); p < mParticles.end(); ){
  p -> update();

 if ( p -> isDead() ) {  // do stuff if particle is dead
    p = mParticles.erase(p);// pass a new valid iterator 
    int addtwo = 2;
     if ( mParticles.size() + addtwo > mParticles.capacity() ) { // if +2 new particles are more than the capacity, then resize to double the capacity
        mParticles.resize(mParticles.capacity()*2);
    } else { // otherwise just add two new particles
        addParticles(addtwo);
        p++;// we move to the next index.
     }
   }
 }

  pink = mParticles.capacity(); // for cout
}
1 Like

Thanks sheva_29,

I’ve tried your suggestion and some other one’s on stackoverflow, the http://en.wikipedia.org/wiki/Erase–remove_idiom in particular didn’t seem to work.
What worked for me is this:

void ParticleController::update() {
for (int p = mParticles.size()-1 ; p >= 0; p--) {
mParticles[p].update();
    if (mParticles[p].isDead()) {
    mParticles.erase( mParticles.begin() + p );
    if (mParticles.size() < 5000) { addParticles(2); }
    }
}
pink = mParticles.capacity();
}

Coming from processing this makes sense to me as this is how I’d treat an arraylist. Loop through it from the end and erase elements. I understand how that can be slower compared to erase/remove idiom way (which I can’t get to work).

How would I implement something like this outside of a particleController class loop:

mParticles.erase( std::remove_if(mParticles.begin(), mParticles.end(), mParticles[p].isDead()), mParticles.end() );

Since calling it for every single element there seems redundant or equal to what I have working already. As I understand it this re-structures the vector going from start-end and putting the values for erasing at the end. But if I have it in the update it only puts 1 element there, which is basically the same as erasing elements one by one.

I’ve also read that vec.size() is somewhat an old? method to use and not a good one. Why is it? Thanks!

1 Like