1

I am trying use an iterator to go through a set and then do something with the members of that set(if there are any). The problem is that, normally this works, but sometimes, it compares the beginning and the end of an empty set and finds them not to be equal.

The code snippet of interest is:

    for(int i=0;i<input_data.num_particles();i++)
    {
        //loop through pairs contained in particle i's Verlet list
        set<int>::iterator iter;
        for(iter=verlet_vars.verlet()[i].begin();iter!=verlet_vars.verlet()[i].end();iter++)
        {
            //call the force() function to calculate the force between the particles
            force(particles.getpart(i),particles.getpart(*iter),input_data,*iter);  
        }
    }

Sometimes, even though the set contained in verlet_vars.verlet()[i] is empty, the program compares the iterator to the end of the set and finds them not equal, and so it enters the inner loop(ultimately causing the program to crash by trying to call the force() function). What is bizarre is if I do anything with the iterator before the inner loop is called,like doing something like:

iter=verlet_vars.verlet()[i].begin();

then, the comparison for the inner loop always returns true, and the program runs normally.

P.S. the command verlet_vars.verlet()[i] calls a vector of sets, hence the [i]

The verlet() function:

std::vector<std::set<int> > verlet() const {return _verlet;}

Thanks for your time.

hivert
  • 10,579
  • 3
  • 31
  • 56
Kyle
  • 217
  • 2
  • 13
  • Is this a single-threaded program? Does `force()` or `getpart()` modify the set? – Kerrek SB Aug 29 '11 at 21:32
  • 1
    Are you sure you want to use `input_data` to determine the number of elements in `verlet_vars.verlet()`? Why not go from 0 to `verlet_vars.verlet().size()`? – Seth Carnegie Aug 29 '11 at 21:33
  • Can we see the verlet() function? – Benjamin Lindley Aug 29 '11 at 21:34
  • What is the return type of `verlet()` – Martin York Aug 29 '11 at 21:34
  • none of the function calls here are allowed to modify the set and the call to the set is through a function that returns a const vector> – Kyle Aug 29 '11 at 21:34
  • there's no particular reason not to go from 0 to verlet_vars.verlet().size(), but there are many loops in my program that have similar conditions, so I use only this one throughout for ease of anyone in the future reading my code – Kyle Aug 29 '11 at 21:38

2 Answers2

8

Your verlet_vars.verlet() function returns by value, so you actually have two different vectors of sets in play. Comparing iterators of two different containers is undefined. That means it's possible for some arrangements of code to appear to always work, but you're still just lucky if it does.

Some alternatives:

  • Make the function return a vector reference instead:

    std::vector<std::set<int> > const& verlet() const {return _verlet;}
    
  • Call the function once to get a local copy of the vector (or the set) and then work off the local copy during the loop:

    std::set<int> verlet_i = verlet_vars.verlet()[i];
    set<int>::iterator iter;
    for(iter=verlet_i.begin();iter!=verlet_i.end();iter++)
    
Community
  • 1
  • 1
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
0

It may not be of importance, depending on whether your compiler does copy or not the returning value. You should be using a const reference on the return type of verlet(). If not, you may end up receiving a different copy with each call, that (depending on the implementation) may cause the iterators not being compared exactly (for instance, comparing an iterator of a set with the end iterator of another set, because each time you call verlet() you get a different copy of the set.)

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87