Подтвердить что ты не робот

Как я могу удалить элементы из 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;
}
4b9b3361

Ответ 1

Вам лучше использовать итераторы для этого:

// Remove all odd numbers from a QList<int> 
QMutableListIterator<int> i(list);
while (i.hasNext()) {
    if (i.next() % 2 != 0)
        i.remove();
}

Ответ 2

Если вы вообще не хотите копировать, используйте итераторы. Что-то вроде:

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

(И убедитесь, что вы действительно хотите использовать QList вместо QLinkedList.)

foreach действительно приятно, когда вы хотите пройти коллекцию для проверки, но, как вы ее нашли, трудно понять, когда вы хотите изменить структуру базовой коллекции (а не значения, хранящиеся там). Поэтому я избегаю этого в этом случае, просто потому, что не могу понять, безопасно ли это или сколько происходит накладные расходы.

Ответ 3

Если тестовая функция реентерабельная, вы также можете использовать QtConcurrent для удаления "плохих" элементов:

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

Или вариант STL:

#include <algorithm>
...
fooList.erase(std::remove_if(fooList.begin(), fooList.end(), bad), 
              fooList.end());