C++ 和 Qt 6.2 中的 For 循环错误行为

For Loop Misbehavior in C++ and Qt 6.2

首先,我是 C++ 和 Qt 的初学者,我使用的是 Qt 6.2 和 C++11。这是我遇到问题的代码:

QSet<QList<QString>> listSet;
for(int i = 0; i < 10; i++)
{
    QList<QString> myList;
    for(int r = 0; r < 10; r++)
    {
        myList << "Item" + QString::number(r);
    }
    listSet.insert(myList);
}

qInfo() << listSet.count();

我原以为我会得到“10”的输出,但我却得到了“1”。我将代码更改为此并解决了问题,但我就是无法理解它:

QSet<QList<QString>> listSet;
for(int i = 0; i < 10; i++)
{
    QList<QString> myList;
    myList << "default" + QString::number(i);
    for(int r = 0; r < 10; r++)
    {
        myList << "Item" + QString::number(r);
    }
    listSet.insert(myList);
}

qInfo() << listSet.count();

我想知道为什么 C++ 会这样。

想想这个:

using StringList = QList<QString>;
using SetOfStringLists = QSet< StringList >;

所以你正在定义一组字符串列表。

然而,您在内部循环中创建的所有列表都完全相同。

所以套装只会保留一个!这实际上是预期的行为。

添加更改时

myList << "default" + QString::number(i);

然后你让每个添加的项目都是唯一的,因为 i 在外循环中!

我编译了 运行 你的第一个例子修改如下

#include <QSet>
#include <QList>
#include <QDebug>

int main() 
{
QSet<QList<QString>> listSet;
for(int i = 0; i < 10; i++)
{
    QList<QString> myList;
    //myList << "default" + QString::number(i);
    for(int r = 0; r < 10; r++)
    {
        myList << "Item" + QString::number(r);
    }
    listSet.insert(myList);
    qInfo() << myList;
}
qInfo() << listSet.count();
}

它输出

$ ./testqt
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
1

当您注释掉您添加的那一行时,它会变成

$ ./testqt
("default0", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default1", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default2", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default3", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default4", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default5", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default6", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default7", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default8", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
("default9", "Item0", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")
10

QSet 是唯一对象的集合。截断的第一个代码产生 10 个彼此相等的 myList 个对象。因此,QSet 只得到一个唯一的 myList 对象:qInfo() << listSet.count(); 输出 1.

第二个代码片段不等于 myList 个对象,它们与第一个列表项不同,qInfo() << listSet.count(); 输出 10。

QSet基于hash

QSet基于hash;如果两个项目的哈希值相等,那么 QSet 将 而不是 开辟一个新的 space。而QList的hash计算方式是基于它的元素

换句话说,如果两个QList有相同的元素,它们就会有相同的hash。而且,因为它们有相同的散列,QSet 不会开辟一个新的 space.

从您的第一个代码开始:每个 qlist 都具有与以下相同的元素:

{"Item0","Item1","Item2","Item3",....}

因为它们有相同的元素,所以它们会有相同的散列。最后,QSet将只有一个元素。

但是,在你的第二个代码中,每个 qlist 都有不同的散列:

qlist0: {"default0", "Item0", "Item1", ...}
qlist1: {"default1", "Item0", "Item1", ...}
...
...

正如你所看到的,每个qlist的第一个元素都是不同的,因此它们会有不同的散列,QSet会为每个qlist开辟一个新的space。