2016-03-05 2 views
0

de Salut les gens à stackoverflow,C++ Comment effacer objet en utilisant le vecteur avec auto en boucle à l'intérieur

Je me demandais s'il y avait des moyens faciles pour: contrôlé iterator ont varié pour boucles pour effacer correctement les objets de dans ses conteneurs en y accédant; en utilisant l'auto.

Pour une norme contrôlée indexé pour la boucle, je ferais quelque chose comme ceci:

void del(int i){ 
    cout<<"Deleting: "<<myObjects[i]<<':'<<myObjects[i]->c<<endl; 
    for(unsigned int j = 0; j < allObjects.size();){ 
     if(allObjects[j] == myObjects[i]){ 
      delete allObjects[j]; 
      allObjects[j] = 0; 
      allObjects.erase(allObjects.begin()+j); 
      break;//Found and deleted first instance, escaping for-loop. 
     }else{ 
      ++j; 
     } 
    } 
    myObjects[i]=0; 
    myObjects.erase(myObjects.begin()+i); 
} 

Une auto pour la boucle ressemblerait à quelque chose comme ceci:

void del(int i){ 
    cout<<myObjects[i]<<endl; 
    for(auto it: allObjects) 
     if(it == myObjects[i]){ 
      delete it; 
      it = 0; 
      //allObjects.erase();// Found, needs erasing. 
     } 
    myObjects[i]=0; 
    myObjects.erase(myObjects.begin()+i); 
} 

Je n'ai pas été en mesure pour bien travailler cela et ont eu recours à l'indexation old school (de nombreuses façons de le faire avec un index).

Je peux le supprimer et le mettre à 0, mais comment l'effacer du vecteur et éventuellement du vecteur sans connaître d'index? Je sais que je peux garder une trace de la boucle et le faire en utilisant un compteur, mais cela irait à l'encontre de l'objectif d'utiliser une belle boucle d'itération propre.

S'il ne fallait pas l'enlever dans le vecteur, comment pourrais-je procéder de la même manière facilement après, sinon en ré-accédant au vecteur?

Rien de mal à utiliser les boucles for-driven indexées, je voulais juste savoir s'il y avait une alternative facile en utilisant notre nouvel ami "auto it".

Merci.

+0

Quel est votre objectif? Effacer des éléments à partir de vecteurs est une chose assez courante, alors assurez-vous de lire et de comprendre toutes les questions automatiquement marquées comme «liées» sur le côté droit. En outre, ne pensez pas que parce que vous avez un marteau ('auto') vous devez l'utiliser. –

+0

Dans votre second extrait de code, il ne s'agit pas d'un itérateur mais de myObjects [/ * index correspondant * /] ... peut être trompeur ... basé sur une plage pour les boucles ne fournit pas d'itérateurs – IceFire

Répondre

3

Je suis désolé, mais il n'y a aucun moyen d'effacer les boucles basées sur la gamme. Vous devez utiliser la méthode standard:

for(auto it = allObjects.begin(); it != allObjects.end();) 
{ 
    if(/* condition */) 
     it = allObjects.erase(it); 
    else 
     ++it; 
} 

Voir aussi haut réponse ici: Can we erase the items in range-based for loop in c++11

+0

Très bien, merci. Je me suis dit qu'il y avait une façon de faire autrement que de la façon dont nous l'avons toujours fait. – doingit

+0

Je ne pense pas que ce soit ce que vous voulez. Dans le cas où un objet est supprimé, vous sautez un objet. Parce que l'itérateur est incrémenté à chaque fois. – Jens

+0

merci, corrigé – IceFire

2

au lieu de rouler votre propre boucle, vous pouvez (et devez) utiliser la bibliothèque standard:

allObjects.erase(std::remove(myObjects.begin(), myObjects.end, myObjects[i]), 
       allObjects.end()); 

C'est plus efficace parce que votre algorithme est O (n^2) puisque les éléments sont décalés tout le temps, et il est plus lisible.

Dans votre cas, puisque vous stockez des pointeurs, vous devez supprimer les « objets supprimés » d'abord:

auto r = std::remove(myObjects.begin(), myObjects.end, myObjects[i]); 
for(auto i=r; i != allObjects.end(); ++i) { 
    delete *i; 
} 
allObjects.erase(r, allObjects.end()); 

Ce sera plus simple si vous utilisez des pointeurs intelligents (std:unique_ptr ou std::shared_ptr) parce que vous pouvez sauter la boucle manuelle et utilisez simplement la doublure commune.

+0

Mes intentions étaient seulement de supprimer un élément de myObjects à index i de allObjects, donc je pense que je voudrais utiliser quelque chose comme std :: remove (allObjects – doingit

+0

@doingit Je pense que le commentaire est coupé. pour supprimer un objet, vous devez appeler erase sur le vecteur Si vous savez qu'il y a au plus une occurence, vous pouvez utiliser std :: find au lieu de std :: remove – Jens

+0

Ouais c'était, excuses, mais oui. std :: trouver du travail avec des pointeurs – doingit

0
objects.erase(
    std::remove_if(
     objects.begin(), 
     objects.end(), 
     [](const Object &) -> bool { 
      // Do "some stuff", then return true if element should be removed. 
      return true; 
     } 
    ), 
    objects.end() 
); 

Vous pouvez également utiliser Boost.Range et Lambda.