Как удалить элементы из QList при итерации по нему с помощью foreach?
Я новичок в Qt и пытаюсь выучить идиомы.
на foreach
документация говорит:
Qt автоматически делает копию контейнера, когда он входит в цикл foreach. Если вы измените контейнер во время итерации, это не повлияет на цикл.
но он не говорит как чтобы удалить элемент во время итерации с foreach
. Мое лучшее предположение-что-то вроде:
int idx = 0;
foreach (const Foo &foo, fooList) {
if (bad(foo)) {
fooList.removeAt(idx);
}
++idx;
}
кажется уродливый, чтобы иметь объем idx
вне цикла (и должен поддерживать отдельный счетчик цикла вообще).
кроме того, я знаю, что да глубокое копирование происходит.foreach
копировать QList
, что дешево, но что происходит, как только я удаляю элемент-это все еще дешево или есть дорогая копия-на-модификации происходит?
EDIT: это тоже не похоже на идиоматический Qt.
for (int idx = 0; idx < fooList.size(); ) {
const Foo &foo = fooList[idx];
if (bad(foo)) {
fooList.removeAt(idx);
}
else ++idx;
}
3 ответов
лучше использовать итераторы для этого:
// Remove all odd numbers from a QList<int>
QMutableListIterator<int> i(list);
while (i.hasNext()) {
if (i.next() % 2 != 0)
i.remove();
}
Если вам вообще не нужна копия, используйте итераторы. Что-то вроде:
QList<yourtype>::iterator it = fooList.begin();
while (it != fooList.end()) {
if (bad(*it))
it = fooList.erase(it);
else
++it;
}
(и убедитесь, что вы действительно хотите использовать QList
вместо QLinkedList
.)
foreach
действительно приятно, когда вы хотите пройти коллекцию для проверки, но, как вы обнаружили, трудно рассуждать о том, когда вы хотите изменить структуру базовой коллекции (а не значения, хранящиеся там). Поэтому я избегаю его в этом случае, просто потому, что я не могу понять, безопасно ли это или сколько происходит копирования накладных расходов.
Если тестовая функция является реентерабельной, вы также можете использовать QtConcurrent для удаления "плохих" элементов:
#include <QtCore/QtConcurrentFilter>
...
QtConcurrent::blockingFilter(fooList, bad);
или вариант STL:
#include <algorithm>
...
fooList.erase(std::remove_if(fooList.begin(), fooList.end(), bad),
fooList.end());