【问题标题】:Proper way to modify Qt data structures using foreach loop [duplicate]使用foreach循环修改Qt数据结构的正确方法[重复]
【发布时间】:2013-07-05 17:29:50
【问题描述】:

我正在使用foreach 循环遍历QLinkedList,但如果项目符合特定条件,我需要删除它们。在不搞乱循环的情况下,正确的方法是什么?

foreach( Object obj, myLinkedList )
{
    if( obj.val == BAD_VAL )
        // remove the item from myLinkedList
}

我找到了other questions这样的地址,但不适用于链表等一般情况。

如果可能的话,我还想了解其他数据结构(如QSetQHash 等)。谢谢

【问题讨论】:

  • @hyde 我在我的问题中链接到那个问题,指出它没有解决我所问的全部问题。 QListQLinkedList 之间存在差异。它们相似,但相同。
  • 嗯,据我所知,它确实回答了这个问题。当您使用其foreach 时,Qt 会获取容器的浅拷贝。如果修改原始容器结构,Qt 需要对整个容器进行新的深拷贝(copy on write 语义)。简而言之,不要为此使用foreach。每个 Qt 容器的语义都是相同的。

标签: c++ qt foreach qt4 iterator


【解决方案1】:

针对具体情况:

显然foreach 循环根本不应该用于修改列表,因为foreach 循环实际上是在处理原始列表的副本。如果修改它,不仅会因为隐式共享和写时修改而受到惩罚,而且一旦退​​出循环,您的更改也会被丢弃。

实现这一点的正确方法是使用迭代器。我更喜欢 Java 风格的迭代器。您会注意到,每种列表类型都有提供简单迭代器的迭代器类。对于QLinkedList 示例,有一个类QMutableLinkedListIterator。可以这样使用:

来自Qt documentation,添加了我的 cmets:

 QMutableLinkedListIterator<int> i(list); // pass list as argument
 while (i.hasNext()) { 
     int val = i.next();                  // retrieve value of current item
     if (val < 0) {
         i.setValue(-val);                // change/set value of current item
     } else if (val == 0) {
         i.remove();                      // delete current item
     }
 }


对于一般情况:

如果您使用的是 QLinkedList 以外的 Qt 数据结构,那么很有可能有一个迭代器类适合您。如果要修改列表,请使用可变版本。这些 API 大致相同。以下是课程:

Structure    |   Immutable Case       |  Mutable Case
-----------------------------------------------------
QList        |   QListIterator        |  QMutableListIterator 
QLinkedList  |   QLinkedListIterator  |  QMutableLinkedListIterator 
QHash        |   QHashIterator        |  QMutableHashIterator
QMap         |   QMapIterator         |  QMutableMapIterator 
QSet         |   QSetIterator         |  QMutableSetIterator 
QStringList  |   QStringListIterator  |  QMutableStringListIterator 
QVector      |   QVectorIterator      |  QMutableVectorIterator

【讨论】:

    【解决方案2】:

    我还可以建议一种昂贵但简单的方法来做到这一点。创建另一个列表并将 good 对象复制到其中。然后用新列表替换旧列表。

    QLinkedList<Object> new_list;
    foreach(Object obj, myLinkedList) {
      if(obj.val != BAD_VAL) {
        new_list << obj;
      }
    }
    list = new_list;
    

    如果您的列表内容很大,请不要这样做。

    【讨论】:

      猜你喜欢
      • 2015-07-04
      • 2018-10-21
      • 1970-01-01
      • 2013-11-18
      • 2010-11-10
      • 1970-01-01
      • 2020-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多