0

I have a Particle struct that I do calculations on:

struct Particle {
   Vector3 Pos;

   void UpdatePosition();
};

I also have a struct ParticleGroup which consists of two Particle objects. When calling UpdatePositions(), both particle positions are updated.

struct ParticleGroup {
    Particle *p1 = NULL;
    Particle *p2 = NULL;

    ParticleGroup(Particle &p1, Particle &p2);
    void UpdatePositions();
};

Now if I create a Particle and a ParticleGroup objects like this:

Particle p1;
Particle p2;
ParticleGroup pGroup(p1, p2);

And then update the position of p1 using Particle::UpdatePosition() method, its new position is going to be reflected in pGroup. And vice versa if I call Particle::UpdatePositions() method.

However if I create an array of Particle objects and an array of ParticleGroup objects using std::vector:

vector<Particle>particles;
vector<ParticleGroup>pGroups;

Now each vector gets their own copy of Particle object and updating the position in one vector will not get reflected in another.

Is there a way to create arrays of these structs and still have the changes in the particle positions reflected?

3
  • 1
    I would do it like this: Every Particle group has a startIdx and endIdx (uint) into the particles vector. You have to do some extra work to keep the particles vector and groups in sync, but at update time you can iterate very efficiently over the groups particles. Commented Nov 28, 2019 at 14:30
  • It's unclear why you would think that changes to the particles in the vector would not be reflected in the particle groups that point to them. Commented Nov 28, 2019 at 14:32
  • @OneManMonkeySquad The solution with the indices could very well work for me, thanks! Commented Nov 28, 2019 at 14:39

3 Answers 3

2

Sure, you have a few options.

  1. If you have advance knowledge of how many total particles you’d need, you could use vector::reserve to preallocate storage for those particles without changing the logical size of the vector. You’d then never need to worry about the Particle objects getting moved around in memory as new particles are added.

  2. Alternatively, don’t directly store Particle objects in your vector. Instead, make a vector<shared_ptr<Particle>> or something to that effect, with the vector storing pointers to the Particles. Now, whenever the vector resizes, the locations in memory of the existing Particles won’t change.

Hope this helps!

Sign up to request clarification or add additional context in comments.

Comments

1

The vector can relocate the storage for the elements as it grows. Therefore you cannot store a pointer to them because they can invalidate. If it's a fixed size, this can be worked around by preallocating.

In addition to shared_ptr (as already mentioned, which works but is a heavy solution), consider storing the particle's index - a great alternate for a pointer, but requires access to the vector to resolve. Something like this:

struct ParticleGroup {
    int pIdx1 = -1;
    int pIdx2 = -1;

    ParticleGroup(int p1, int p2);
    void UpdatePositions(std::vector<Particle> const& particles) {
        if (pIdx1 != -1) {
            particles[pIdx1].updatePosition();
        }
        ...
    }
};

That's enough to give the idea, even though the actual vector could be abstracted away better, stored as a member, etc.

Comments

0

Objects with pointets in vectors are no different from objects with pointers anywhere else. You need to decide what happens when you copy an object with pointers, and you need to decide what happens when you copy pointed-to objects. And you may want to decide what kind of pointer or pointer-like object works best (regular pointers may not be the best kind).

In your case you probably never want to copy the pointed-to objects (the particles). Such copying doesn't make a lot of sense in the context of your application. So you want to store and pass around some proxy objects instead. Such proxy objects may take several forms.

  1. Smart pointers (std::shared_ptr or similar).
  2. Regular pointers.
  3. Indices in some global array.
  4. Iterators in some global container.

I would say the first option is the best in most cases so it should be your default choice.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.