Reputation: 617
I am iterating over the rows of a 2D array (lib) and comparing the first 4 entries in each row to a vector of tuples (near_pts) containing 4 elements. Basically, I want to extract all rows from lib where the first 4 elements (in that row) match any of the tuples in near_pts, and add these rows to a new 2D array (sub_lib). There should not be any repeats in lib or near_pts.
When a tuple from near_pts is matched in lib, I want to erase it from near_pts so that no time is wasted trying to match that particular tuple. I would expect that, since I have a break statement immediately after the erase, we would go to the next iteration of the exterior for loop and the iterator over near_pts would be reset to handle the modified version of near_pts. However, this doesn't seem to be happening, a few of the tuples are never matched (and there should always be a match). I know the problem is related to the iterator because my debugging efforts have shown that the iterator sometimes only loops over 1 element near_pts when multiple elements still exist, but I cannot figure out why this happening. The code is below, please let me know if more information and/or clarity is needed.
int n = 0;
for (int i=0; i<numPts; i++) {
for (vector<my_tup>::iterator it = near_pts.begin(); it != near_pts.end(); it++) {
bool match = (get<0>(*it)==lib[i][0] && get<1>(*it)==lib[i][1] &&
get<2>(*it)==lib[i][2] && get<3>(*it)==lib[i][3]);
// If there is a match, add it to the sub-library, erase the entry
// from near_pts, and exit the interior loop.
if (match) {
for (int j=0; j<numLibCols; j++) { sub_lib[n][j] = lib[i][j]; }
n++;
near_pts.erase(it);
break;
}
// If we have found all of the tuples, exit the loop.
if (n==near_pts.size()) { break; }
}
}
Notes: lib is effectively a 2D array of size numPts x 13, near_pts is a vector of my_tup, where my_tup is a tuple< double,double,double,double >, and sub_lib is a 2D array of size near_pts.size() x 13, where this size is set before any of the elements of near_pts are erased.
Upvotes: 0
Views: 113
Reputation: 462
Erasing during iteration in a vector invalidates the iterator, so you need to update it. Doing this also eliminates the check for n
at the end because when near_pts
is empty, the iterator must be at near_pts.end()
.
int n = 0;
for (int i=0; i<numPts; i++) {
vector<my_tup>::iterator it = near_pts.begin();
while(it != near_pts.end()) {
bool match = (get<0>(*it)==lib[i][0] && get<1>(*it)==lib[i][1] &&
get<2>(*it)==lib[i][2] && get<3>(*it)==lib[i][3]);
// If there is a match, add it to the sub-library, erase the entry
// from near_pts, and exit the interior loop.
if (match) {
for (int j=0; j<numLibCols; j++) { sub_lib[n][j] = lib[i][j]; }
n++;
it = near_pts.erase(it);
break;
}
else {
++it;
}
}
}
Upvotes: 1
Reputation: 153820
Using
near_pts.erase(it);
invalidates it
. Any use of the iterator it
after this operation has undefined behavior. You may want to use
near_ptrs.erase(it++);
instead: this way the iterator it
is moved off the erased element before it is erased. Of course, you can't unconditionally increment it
after using that statement.
Upvotes: 0
Reputation: 3103
Your final condition
// If we have found all of the tuples, exit the loop.
if (n==near_pts.size()) { break; }
is incorrect as near_pts gets decreased and n gets increased on each match.
You probably want to check something like if (near_pts.empty()) break;
Upvotes: 2