Why does my delete function crash? I've used the same algorithm for other 2D vectors and it works perfectly fine..

I'm trying to remove an array of vectors from a 2D vector all of the std::string type.

//Ripped out of a massive class I wrote.

vector<vector<string>>& Delete(vector<string> StringArrayToDelete, bool CaseSensitive = true, bool All = false)
        {
            vector<vector<string>> Temp = S2DA;     //S2DA is a vector<vector<string>>
            //The below works perfectly fine..
            if (!CaseSensitive)
            {
                for (unsigned short I = 0; I < StringArrayToDelete.size(); I++)
                    for (unsigned short J = 0; J < StringArrayToDelete[I].size(); J++)
                        StringArrayToDelete[I][J] = tolower(StringArrayToDelete[I][J]);

                for (unsigned short I = 0; I < Temp.size(); I++)
                    for (unsigned short J = 0; J < Temp[I].size(); J++)
                        for (unsigned short K = 0; K < Temp[I][J].size(); K++)
                            Temp[I][J][K] = tolower(Temp[I][J][K]);
            }

            //problem is actually here..
            for (unsigned I = 0; I < Temp.size(); I++)
            {
                if (Temp[I] == StringArrayToDelete)
                {
                    S2DA.erase(S2DA.begin() + I);
                    if (!All)
                        break;
                    I = 0;
                }
            }
            return *this;
        }

Edited 4 Years Ago by triumphost: n/a

I would guess that All true is a problem. If you have multiple vector<string> that equal the one you are trying to delete, then after the first delete (S2DA.erase(S2DA.begin() + I)) takes place Temp and S2DA are no longer insync. What I mean is you have reduced the size of S2DA by one but Temp still has the same number for the size (I). So when you find the next Temp that matches StringArrayToDelete the value where that string to delete in Temp is not where it is in S2DA.
Here is an example:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

void printVec(vector<vector<string> > &v){
   vector<vector<string> >::iterator p1(v.begin());
   vector<string>::iterator p2;
   int i(0);
   for (;p1 != v.end(); p1++) {
      cout << "[" << i++ << "]: ";
      for(p2=p1->begin();p2 != p1->end(); p2++){
          cout << *p2 << ",";
      }
      cout << endl;
  }
}
int main(){
   vector< vector<string> > S2DA,Temp;
   vector<string> a,b,c,StringArrayToDelete;
   a.push_back("Test");
   a.push_back("one");
   b.push_back("Test");
   b.push_back("one");
   c.push_back("Test");
   c.push_back("two");
   S2DA.push_back(a);
   S2DA.push_back(b);
   S2DA.push_back(c);
   Temp = S2DA;
   StringArrayToDelete = a;
   //problem is actually here..
   for (unsigned I = 0; I < Temp.size(); I++) {
       if (Temp[I] == StringArrayToDelete) {
           cout << "Before erase(" << I << ")" << endl;
           printVec(S2DA);
           S2DA.erase(S2DA.begin() + I);
           cout << "After erase(" << I << ")" << endl;
           printVec(S2DA);
           // If I leave this in I get a SegFault
           //I = 0;
       }
   }
   cout << "---------------------" << endl;
   cout << "Final Result is worng!!" << endl;
   printVec(S2DA);
  return 0;
}

Output:

$ ./a.out
Before erase(0)
[0]: Test,one,
[1]: Test,one,
[2]: Test,two,
After erase(0)
[0]: Test,one,
[1]: Test,two,
Before erase(1)
[0]: Test,one,
[1]: Test,two,
After erase(1)
[0]: Test,one,
---------------------
Final Result is worng!!
[0]: Test,one,
$

Forgot the reason:
http://www.cplusplus.com/reference/stl/vector/erase
"Because vectors keep an array format, erasing on positions other than the vector end also moves all the elements after the segment erased to their new positions, which may not be a method as efficient as erasing in other kinds of sequence containers (deque, list)."

Try:

//problem is actually here..
   int numDeletes(0);             // <------------- Keep track of erases
   for (unsigned I = 0; I < Temp.size(); I++) {
       if (Temp[I] == StringArrayToDelete) {
           cout << "Before erase(" << I << ")" << endl;
           printVec(S2DA);
           S2DA.erase(S2DA.begin() + I-numDeletes++);   // <------- Backup the number of erases
           cout << "After erase(" << I << ")" << endl;
           printVec(S2DA);
           // If I leave this in I get a SegFault
           //I = 0;
       }
   }

Output:

$ ./a.out
Before erase(0)
[0]: Test,one,
[1]: Test,one,
[2]: Test,two,
After erase(0)
[0]: Test,one,
[1]: Test,two,
Before erase(1)
[0]: Test,one,
[1]: Test,two,
After erase(1)
[0]: Test,two,
---------------------
Final Result is [B]RIGHT[/B]!!
[0]: Test,two,

Edited 4 Years Ago by histrungalot: n/a

Comments
I solved it differently.. but yours works too :D
This article has been dead for over six months. Start a new discussion instead.