0

I have a class, like this:

class Particle()
{

    void CalcSomething(Super& arg){
        for(unsigned long long index = 0; index < arg.NumberOfParticle(); index ++){                              
            if(this != arg.ParticleMemoryPointer(index)){
                // Do the calculations
            }
        }
    }

}

And the following class holds the particles:

class Super()
{

    const Particle* const ParticleMemoryPointer(unsigned int index)
    {
        std::list<Particle>::iterator iter = mParticles.begin();
        std::advance(iter, index);
        return &(*iter);
    }

    std::list<Particle> mParticles;
}

The idea being, the instance of a particle, which is calling CalcSomething needs to detect when CalcSomething is being called from the same instance of Particle as the one addressed by the index inside the function CalcSomething. (Does that make sense? I haven't worded it very well...)

You realize the reason for this is if we are to do a calculation between two particles, we need to make sure they are different particles.

Some cout statements show the memory address returned by ParticleMemoryPointer is not the same as the this pointer for the case when there is one item in the list. (They should be, with one item, we are doing a calculation with the same particle twice.)

I hope this is understandable.

Edit The function inside Super which calls CalcSomething:

void Super::UpdateParticles(double time_step)
{
    std::list<Particle>::iterator iter = mParticles.begin();

    for(unsigned long long index = 0; index < mParticles.size(); index ++){
        std::advance(iter, 1);
        iter->CalcSomething(*this);
    }
}

Edit 2 We can't use std::vector. (We know you were thinking it!)

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • 1
    Be careful - you're passing an `unsigned long long` in to ParticleMemoryPointer as an `unsigned int`. – Scott Mermelstein Feb 27 '13 at 23:30
  • Are you sure you're passing the same super object to the CalcSomething? possibly you've accidently passed a copy of the original super. – MerickOWA Feb 27 '13 at 23:33
  • This is a terribly inefficient way to loop over every pairing of particles. `advance` on a `list` iterator. Shudder. – Peter Wood Feb 27 '13 at 23:41
  • @PeterWood The bloke in charge doesn't care how long it takes, so long as we fit a hell of a lot of objects into memory. – FreelanceConsultant Feb 27 '13 at 23:49
  • std::list has _much_ more per-item overhead than std::vector (which has exactly 0). If you're worried about not being able to allocate enough contiguous storage, use an std::deque – Bwmat Feb 27 '13 at 23:57
  • @Bwmat List is just for testing purposes. We will do some work on making lists of vectors, which I guess is kind of like a deque. One step at a time though. – FreelanceConsultant Feb 27 '13 at 23:59

2 Answers2

1

After you insert an element into a list, its pointer will never be invalidated as long as that list and that element exist. See this answer for more info: Pointers to elements of std::vector and std::list

Just make sure that after you insert into the list, you're not comparing the original, uninserted element with the inserted one - insertion will move or copy the element into the list.

For your intended purpose, I can't help but feel there's an easier method, one that doesn't require Particle to know anything about Super, and even without checking pointers:

(pseudocode)

for particle in particles(start, end - 1):
    for otherParticle in particles(particle + 1, end)
        DoSomething(particle, otherParticle)
Community
  • 1
  • 1
congusbongus
  • 13,359
  • 7
  • 71
  • 99
  • @PeterWood, work is usually a word people use to describe something which operates as expected, however that may be. In this case, the expected, or desired, behaviour is that `this != arg.ParticleMemoryPointer(index)`. I hope that clears things up for you. – FreelanceConsultant Feb 27 '13 at 23:56
  • @EdwardBird Snarkiness aside (have you folks had your coffee?) pointers will not change once inserted into a list, so yes comparing pointers will work. – congusbongus Feb 28 '13 at 00:02
  • @EdwardBird I apologise, I was forgetting my principles. – Peter Wood Feb 28 '13 at 00:04
  • @CongXu No coffee, we are about to go to bed. We simply don't tolerate those who won't use their brains before adding nonsense/spam/unhelpful comments. It's quite clear from the code in the question, albeit not the explanation, how it should `work`. Apologies for any offence caused. Thank you for your input, it is helpful to know the comparison of pointers should work. I will look into it tomorrow. – FreelanceConsultant Feb 28 '13 at 00:05
  • @PeterWood I am glad you appreciate my sense of humour. – FreelanceConsultant Feb 28 '13 at 00:08
  • @EdwardBird I meant odd really. You seem intent on insulting the people that you need help from. Quite odd. – Peter Wood Feb 28 '13 at 00:12
0
template<typename Iter, typename Func>
void pair_wise(Iter it, Iter last, Func func) {
    while(it != last) {
        Iter other = it;
        ++other;
        while(other != last) {
            func(*it, *other);
            ++other;
        }
        ++it;
    }
}

This will iterate for example with 4 values 1, 2, 3, 4 and pair them:

(1, 2), (1, 3), (1, 4)
(2, 3), (2, 4)
(3, 4)

You can use it with a lambda function in C++11:

int main() {
    list<Particle> particles;

    pair_wise(particles.begin(), particles.end(),
              [](Particle& lhs, Particle& rhs) {
                  lhs.doSomething(rhs);
              });                  
}

Or pre-C++11, for example, with a function pointer:

void calcSomething(Particle& lhs, Particle& rhs) {
    lhs.calcSomething(rhs);
}

int main() {
    list<Particle> particles;

    pair_wise(particles.begin(), particles.end(),
              calcSomething);                  
}
Peter Wood
  • 23,859
  • 5
  • 60
  • 99