In the last month or so, I’ve begun messing around with making apps on the iPhone using the great openFrameworks for iPhone. In most cases so far, this has meant coding almost exclusively in C++ unless I need access to some kind of SDK functionality that hasn’t yet been integrated into ofxiPhone (like sound!).
Anyway, I spend a lot of time using Processing/Java and my typical workflows when building projects involve using ArrayLists to add and get rid of objects during runtime. As it turns out, C++ has a collection that is pretty similar to an ArrayList and its called a “vector”, which is confusing because vectors are also what you’d use to store things like velocity, positions and any kind of forces, right?
What with all of C++’s super-close-to-the-hardware memory management, its not a big surprise that working with vectors takes a little more effort on your part than using an ArrayList. Nothing that follows here is “l33t” and I’ll bet I’m not even doing things the optimal way, but it works and I think it will be helpful if you are used to using ArrayLists (or even ActionScript 3 Arrays).
For the sake of this example going forward, let’s say we’re using our vector to store instances of a class called “Noodle”.
Lesson 1: Use pointers
I found out the hard way that you should store pointers in your vectors and not the objects themselves. It turns out that when you are removing an object a vector using the erase() method, that objects destructor gets called automatically and you may not want that to happen. Better to do that manually if its what you need.
First, don’t forget to import the vector header at the beginning of your source file so you can use it:
#include <vector>
So, here is how I’ll declare the vector:
vector<Noodle*> noodles;
Lesson 2: adding instances
Somewhere in your code, you’ll want to add new objects to your vector. Maybe inside a mouse press or a finger touch?
Noodle* noodle = new Noodle();
noodle->init(positionX, positionY);
noodles.push_back(noodle);
Got that? I made a noodle and then initialized it with some position coordinates and then put it in the vector using the push_back() method (its the equivalent of the ArrayList’s add() method).
Lesson 3: iterating through the vector
So let’s say we’ve got a bunch of noodles in our vector now and we want to do something with them. Anything! Iterating through a vector is slightly more involved than an ArrayList because you need an iterator object to take you through. Its not that hard though:
vector<Noodle*>::iterator iter;
for ( iter = noodles.begin(); iter != noodles.end(); iter++ )
{
Noodle* noodle = (*iter);
noodle->update();
noodle->doAwesomeThings();
noodle->whateverYouGetTheIdea();
}
Now, inside that for loop, I also could have called those methods off of the de-referenced iterator like this:
(*iter)->anotherCoolMethod();
But it reads a bit more clearly if you have a locally scoped little pointer like above. Right?
Lesson 4: taking stuff out (aka Noodle Take-Out)
This is the part that I got a little hung up on, mostly due to the aforementioned consequences of storing instances of objects rather than storing pointers to instances of objects. So, let’s say that when a Noodle dies, it has a variable called “isDead” that becomes true. We’ll want to get rid of all those dead noodles and here is how:
vector<Noodle*>::iterator iter;
for ( iter = noodles.begin(); iter != noodles.end();)
{
Noodle* noodle = (*iter);
if ( noodle->isDead )
{
iter = noodles.erase(iter);
// maybe you want to get rid of the noodle
if ( deleteNoodlesForevs )
delete noodle;
// or perhaps you want to store it somewhere else and bring it back to life later
else
deadNoodles.push_back(noodle);
}
else
iter++;
}
Well folks, that is about it for now. Now you can dynamically create objects and then get rid of them when you want to. Hope that was useful.