Details
-
Suggestion
-
Resolution: Fixed
-
Not Evaluated
-
6.6.0
-
None
-
-
4c286d6f6 (dev), e38e517df (6.7)
Description
QHash::operator[] will return a reference to the value in the QHash for the specified key. However unlike std::unordered_map if the QHash is rehashed then that reference gets silently invalidated.
This lead to a very tricky to track down issue for me where I was appending items to a QObjectList in a QHash while adding elements to the QHash and my QObjectList reference would seemingly magically loose all of its elements.
Here is a reproduction case to illustrate the problem:
#include <QtCore/QCoreApplication> #include <QtCore/QHash> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QHash<QObject*, QList<int>> hash; constexpr size_t kQObjectCount = 1000; // I want to insert items into a reference to a list inside the QHash // at the same time as adding elements to the QHash. QObject* currentObject{nullptr}; for (size_t i; i < 64; ++i) { currentObject = new QObject(&a); hash.insert(currentObject, {}); } // Take a reference to a value in the hash. QList<int>& list = hash[currentObject]; list.append(1); list.append(3); list.append(2); Q_ASSERT(hash.capacity() == 64); Q_ASSERT(list.contains(1)); Q_ASSERT(list.contains(2)); Q_ASSERT(list.contains(3)); // Add one more object to the hash to cause a rehash. hash.insert(new QObject(&a), {}); Q_ASSERT(hash.capacity() != 64); list.append(4); list.append(5); list.append(6); // I would expect the list to now contain 1, 2, 3, 4, 5 & 6 // But it doesn't as the reference has been invalidated. Q_ASSERT(list.contains(1)); // <-- This fails. Q_ASSERT(list.contains(2)); Q_ASSERT(list.contains(3)); Q_ASSERT(list.contains(4)); Q_ASSERT(list.contains(5)); Q_ASSERT(list.contains(6)); return 0; }
Either the reference invalidation should be documented somewhere (ideally under https://doc.qt.io/qt-6/qhash.html#operator-5b-5d) or QHash should not invalidate the reference on rehashing like std::unordered_map.