Ответ 1
Вам лучше использовать итераторы для этого:
// Remove all odd numbers from a QList<int>
QMutableListIterator<int> i(list);
while (i.hasNext()) {
if (i.next() % 2 != 0)
i.remove();
}
Я новичок в 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;
}
Вам лучше использовать итераторы для этого:
// 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());