views:

572

answers:

5

Hi,

I have a class named Spring in a particle system. The constructor looks like:

Spring(Particle& _a, Particle& _b);

And I have a vector of Particles and I use

Spring mySpring = Spring(myParticles.at(j),myParticles.at(j+1));

inside a loop to add a spring force between two particles. Everything works fine so far. However, I want to use a 2d vector of Particles. That is:

Spring mySpring = Spring(myParticles.at(i).at(j),myParticles.at(i).at(j+1));

And I don't get a reference to the particle. In the first example, whenever I change the particle in my spring class, the particle in the vector gets changed. In the second example the changes are only locally. How can I change the particles in the 2D Vector?

EDIT: I try to make some things clear:

I have some particle systems and each of them consists of a number of particles. Each particle should only interact with the other particles that are in the same system as itself. Therefore I have a vector of particle systems with each particle sytem being a vector of particle objects. (That makes the 2d vector). The first dimension (i) is the system, the second (j) the individual particle. The particles in the system interact with each other (collide, avoid, whatever..) and their positions change. And the vector gets "updated". (That is, the reference works).

However, i have a second (1d) vector of spring forces. The spring force too is used to update the positions of the particles. My constructor does the following:

Spring::Spring(Particle& _a, Particle& _b) {
    a=&_a;
    b=&_b; }

With a and b being Particle*. So i store pointers to two particles in the 2d vector. Another function Spring.doSpring() changes the positions of the particles.

a->pos.x=300;

or

a->velocity+=something..

In the first example I posted I used only one particle system and so there was no need for a 2d vector. And everything works fine. The particles in the vector gets updated. But with the second example my program runs but somehow no matter what the doSpring function does, the particles in the 2d vector don't get updated.

A: 

If I understand correctly you want to create a 2D array of Particles using std::vector?

If so you can declare it as: std::vector<std::vector<Particle> >. You could then even use [][] nomenclature to access elements. (Danger Will Robinson! No boundary checking while using this operator)

However if this 2D array will contain mostly zeros then it might be ok to use a map with indices as keys.

Marcin Gil
Judging by his code (`.at(i).at(j)`), he's already using a vector of vectors.
Max Shawabkeh
Judging by the examples above, this looks like exactly what he's already trying to do (the "at(...).at(...)" part).
Cwan
A: 

I think this series from C++ FAQ Lite should help.

Please don't be confused by "operator overloading" header. You definitely should read 13.10, 13.11 and 13.12 from there.

Alexander Poluektov
+2  A: 

What you are doing looks OK - the following code creates a "2D" vector and illustrates that the .at().at() construct does give you a reference:

#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector <vector<int> > vi;
    vi.push_back( vector <int>() );
    vi.at(0).push_back( 42 );
    cout << vi.at(0).at(0) << endl;    // prints 42
    vi.at(0).at(0) = 666;
    cout << vi.at(0).at(0) << endl;    // prints 666
}
anon
A: 

Thanks for the answers. But it still doesn't work. And yes, I'm using std::vector > I tried the [][] nomenclature and .at(i).at(j) and either way, the element in the vector doesn't get changed. Does it make a difference whether there are native c++ types like int in the vector or my particle instances?

hrst
You should make additions to your question by editing the question, not by posting an answer. And I think you need to post some code which actually illustrates the at().at() syntax not returning a reference - what does your Spring constructor actually do?
anon
+3  A: 

One of the most common issues taking references/pointers to elements inside vectors is reallocation. If you push_back, for example, it's possible the vector will exceed its capacity, allocate a new block of memory, copy everything over, then free the old block. If you've taken references or pointers to elements inside the vector, these still point to the old block, now dead memory, and is a serious bug!

So I'm guessing your particle effect keeps adding new particles to your particles vector, which at some point causes the vector to reallocate when it exceeds capacity. The pointers stored by the Spring class aren't updated though, so point to dead memory and have no effect on the actual particle, which got moved somewhere else by the vector.

Don't take a reference or pointer to an element inside a vector. Use a vector of pointers, a list, or some other container which isn't going to shuffle around the memory addresses of actual elements. If you have to, use iterators to elements inside a vector. In debug builds, assuming you've got a checked STL implementation, you'll get a debug alert if you access the element through the iterator after the vector reallocates itself.

AshleysBrain
But would't that cause null pointers which would cause the application to crash? Because my application doesn't crash, the elements just don't get updated.However, that's a great answer, I didn't think about the reallocation.
hrst
No, nothing gets set to a null pointer: vector doesn't know about the pointers in the Spring class, so never makes any attempt to change them. The pointers *aren't* modified or null, they just point to a dead memory location. Because the memory is probably somewhere inside your process, read and writes are allowed, despite the fact you're probably corrupting your application's memory.
AshleysBrain