Comment puis-je supprimer des éléments D'une QList tout en itérant sur elle en utilisant foreach?

je suis nouveau à Qt et j'essaie d'apprendre les expressions idiomatiques.

Le foreach documentation dit:

Qt prend automatiquement une copie du récipient lorsqu'il entre dans une boucle foreach. Si vous modifiez le conteneur pendant que vous itérez, cela n'affectera pas la boucle.

mais il ne dit pas comment pour supprimer un élément tout en itérant avec foreach . Ma meilleure supposition est quelque chose comme:

int idx = 0;
foreach (const Foo &foo, fooList) {
  if (bad(foo)) {
    fooList.removeAt(idx);
  }
  ++idx;
}

semble laid pour avoir à portée idx en dehors de la boucle (et de devoir maintenir un compteur de boucle séparé du tout).

aussi, je sais que foreach fait une copie du QList , qui est bon marché, mais ce qui se passe une fois que j'enlève un élément -- est-ce encore bon marché ou est-ce qu'il y a une copie-sur-Modifier cher en cours? Oui, copie en profondeur qui se passe .

EDIT : Cela ne semble pas être idiomatiques Qt.

for (int idx = 0; idx < fooList.size(); ) {
  const Foo &foo = fooList[idx];
  if (bad(foo)) {
    fooList.removeAt(idx);
  }
  else ++idx;
}
39
demandé sur Daniel Brunner 2011-12-23 12:22:54

3 réponses

Vous devriez mieux utiliser des itérateurs :

// Remove all odd numbers from a QList<int> 
QMutableListIterator<int> i(list);
while (i.hasNext()) {
    if (i.next() % 2 != 0)
        i.remove();
}
43
répondu Igor Oks 2015-10-29 14:43:25

si vous ne voulez pas de copie, utilisez des itérateurs. Quelque chose comme:

QList<yourtype>::iterator it = fooList.begin();
while (it != fooList.end()) {
  if (bad(*it))
    it = fooList.erase(it);
  else
    ++it;
}

(Et assurez-vous que vous voulez vraiment utiliser un QList au lieu de QLinkedList .)

foreach est vraiment agréable quand vous voulez traverser une collection pour l'inspection, mais comme vous l'avez constaté, il est difficile de raisonner sur, lorsque vous voulez changer la structure de la collection sous-jacente (pas les valeurs stockées). Donc je l'évite dans ce cas, simplement parce que je n'arrive pas à savoir si c'est sûr ou combien de copie se produit.

17
répondu Mat 2011-12-23 08:39:27

si la fonction de test est reentrant, vous pouvez également utiliser QtConcurrent pour supprimer les" mauvais "éléments:

#include <QtCore/QtConcurrentFilter>
...
QtConcurrent::blockingFilter(fooList, bad);

ou la variante STL:

#include <algorithm>
...
fooList.erase(std::remove_if(fooList.begin(), fooList.end(), bad), 
              fooList.end());
9
répondu alexisdm 2011-12-23 09:55:16