2015-11-21 3 views
1

J'essaie actuellement de supprimer 2 éléments d'un vecteur si certaines conditions sont remplies. Je peux supprimer avec succès un seul élément sans l'erreur "vector itérateur non déréférencable", je sais que le problème a été causé en enlevant deux éléments à la fois qui dérange avec les itérateurs mais je ne suis pas sûr de la façon correcte d'enlever plus d'un élément à la fois.Iterator vectoriel efface deux éléments à condition

vector<SomeObj*> objs; 

vector<SomeObj*>::iterator it = objs.begin(); 
while (it != objs.end()) 
{ 
    vector<SomeObj*>::iterator it2 = objs.begin(); 
    bool deleted = 0; 

    while (it2 != objs.end()) 
    { 
     if ((*it)->somecondition(**it2)) 
     { 
      delete *it2; 
      *it2 = NULL; 
      it = objs.erase(it2); 

      delete *it; 
      *it = NULL; 
      it = objs.erase(it); //Will error here due to invalidating the iterator 

      deleted = 1; 
      break; 
     } 
     ++it2; 
    } 

    if (!deleted) 
     ++it; 
} 
+0

Quelle est la situation actuelle? – developerbmw

+0

si les deux éléments sont de la même taille – user3424480

Répondre

2

Le problème est que le premier appel à effacer() peut très bien invalider l'autre itérateur. Voir ce post pour un résumé rapide de ce qui est invalidé dans divers conteneurs. Je dirais que la solution la plus simple consiste à traverser d'abord le conteneur et à marquer les entrées à effacer, mais ne les efface pas, puis dans un second balayage, efface tout ce qui a été marqué. Pour des raisons de performances lors de cette seconde analyse, vous devez utiliser std :: remove_if ou utiliser l'itérateur inverse.

1

Travailler avec des itérateurs imbriqués est délicat si vous mutez le conteneur.

J'ai mis en place un exemple de code qui fait ce que vous voulez. Ce que je fais est de retarder la suppression en définissant les éléments à supprimer à nullptr puis en supprimant ceux que nous rencontrons dans les boucles.

#include <iostream> 
#include <vector> 

class Example 
{ 
public: 
    Example(int size) : size(size) {} 

    bool somecondition(const Example& other) const 
    { 
     return size == other.size; 
    } 

    int size; 
}; 

int main() 
{ 
    std::vector<Example*> vec; 

    vec.push_back(new Example(1)); 
    vec.push_back(new Example(2)); 
    vec.push_back(new Example(3)); 
    vec.push_back(new Example(2)); 

    for (auto it1 = vec.begin(); it1 != vec.end();) 
    { 
     if (!*it1) 
     { 
      it1 = vec.erase(it1); 
      continue; 
     } 

     for (auto it2 = vec.begin(); it2 != vec.end(); ++it2) 
     { 
      if (!*it2) 
      { 
       vec.erase(it2); 

       // we need to start the outer loop again since we've invalidated its iterator 
       it1 = vec.begin(); 
       break; 
      } 

      if (it1 != it2 && (*it1)->somecondition(**it2)) 
      { 
       delete *it1; 
       *it1 = nullptr; 

       delete *it2; 
       *it2 = nullptr; 

       break; 
      } 
     } 

     ++it1; 
    } 

    for (auto example : vec) 
    { 
     std::cout << example->size << std::endl; 
    } 

    return 0; 
}