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 Oui, copie en profondeur qui se passe . 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?
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;
}
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();
}
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.
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());