简体   繁体   中英

Erasing elements of a vector within two for loops

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.

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;

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;
    }
  }
}

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.

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