简体   繁体   中英

How can it be that the std::vector distance Function gives a higher value than .size()?

I have the following code, where myFields is a std::set of pairs and currentSet is a std::vector of pairs, which has a very strange behavior: After a iteration where the condition is true, the size of currentSet gets increased as I expect from 1 to 2, but very strangely the distance in the for loop from the current iterator does not go from 1 to 2 as well as I expect, but suddenly to 6. This causes my code to crash after the next iteration, because there are not more than 2 elements in the vector, so it will try to read unallocated memory.

vector<pair<int,int>> currentSet;

currentSet.push_back( *(myFields.begin()) );
myFields.erase( myFields.begin() );

for ( auto iterator=currentSet.begin(); iterator != currentSet.end(); ++iterator ) {

    set<pair<int,int>>::iterator topright = myFields.find( pair<int,int>( i, j+1 ) );

    if ( topright != myFields.end() ) {
        cout << "size " << currentSet.size() << endl;    // gives 1
        cout << "dist to end " << distance(iterator, currentSet.end()) << endl;    // gives 1
        UniqueInsertion(currentSet, *topright, myFields );
        cout << "size " << currentSet.size() << endl;    // gives 2
        cout << "dist to end " << distance(iterator, currentSet.end()) << endl;    // gives 6!?


    }
}

Where UniqueInsertion is the following function:

void UniqueInsertion(vector<pair<int,int>> &vect, const pair<int,int> &elem, set<pair<int,int>> &fields) {

  if(find(vect.begin(), vect.end(), elem) == vect.end()) {
      vect.push_back(elem); 
      fields.erase(elem);
  }
}

This problem has only shown up when I changed the Sets from std::set to std::vector, which was necessary because I need back insertion for the loop to work this way. I have not the slightest idea what causes this behavior and would be very grateful for explanation to how this happens, and of course what I can do to fix it.

Cheers!

Because you're use push_back on currentSet :

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.

In fact, std::vector stores its array contiguously in memory.

For that, it allocates an array of an arbitrary size (to avoid to reallocate at each push_back() ).
And when we have performed as many push_back() as the available allocated space, the std::vector reallocates a bigger array to be able to add the new element.

The problem is here, as the std::vector stores its elements contiguously in memory, it needs to copy the already existing data in the new location (the bigger array). Then, the old array is released.
Therefore, if you have an iterator pointing to an element of the vector, after the reallocation, the iterator becomes invalidated and points to a free memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM