41

我是 Qt 的新手,正在尝试学习这些习语。

foreach文档说:

Qt 在进入 foreach 循环时会自动获取容器的副本。如果您在迭代时修改容器,则不会影响循环。

但它没有说明如何在使用foreach. 我最好的猜测是:

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

必须在循环之外进行范围似乎很难看idx(并且必须维护一个单独的循环计数器)。

另外,我知道foreach制作 的副本QList,这很便宜,但是一旦我删除了一个元素会发生什么 - 仍然很便宜还是正在进行昂贵的修改时复制?是的,深拷贝发生了

编辑:这似乎也不像惯用的 Qt。

for (int idx = 0; idx < fooList.size(); ) {
  const Foo &foo = fooList[idx];
  if (bad(foo)) {
    fooList.removeAt(idx);
  }
  else ++idx;
}
4

3 回答 3

53

你应该更好地使用迭代器

// Remove all odd numbers from a QList<int> 
QMutableListIterator<int> i(list);
while (i.hasNext()) {
    if (i.next() % 2 != 0)
        i.remove();
}
于 2011-12-23T08:38:17.683 回答
23

如果您根本不想要副本,请使用迭代器。就像是:

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

(并确保您真的想使用 aQList而不是 a QLinkedList。)

foreach当您想要遍历一个集合进行检查时,这非常好,但是正如您所发现的,很难推断您何时想要更改底层集合的结构(而不​​是存储在其中的值)。所以在那种情况下我会避免它,只是因为我不知道它是否安全或发生了多少复制开销。

于 2011-12-23T08:39:27.123 回答
13

如果测试函数是可重入的,您还可以使用 QtConcurrent 删除“坏”元素:

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

或 STL 变体:

#include <algorithm>
...
fooList.erase(std::remove_if(fooList.begin(), fooList.end(), bad), 
              fooList.end());
于 2011-12-23T09:55:16.100 回答