Примечание. Вы можете найти минимальный рабочий пример в конце этого поста.
Я использую Qt 5.7. Допустим, у меня есть следующие QHash
:
QHash<HashKey, HashValue> hm;
с участием
enum HashKey {
K1,
K2,
K3,
K4,
K5
}
а также
class HashValue {
public:
int x;
HashValue(int x) {
this->x = x;
}
}
Я инициализировал хеш-карту следующим образом:
hm.insert(K1, HashValue((int)K1));
hm.insert(K2, HashValue((int)K2));
hm.insert(K3, HashValue((int)K3));
hm.insert(K4, HashValue((int)K4));
hm.insert(K5, HashValue((int)K5));
Я проверил это, позвонив
cout << hm.value(K4).x << endl;
cout << hm.find(K4).value().x << endl;
Оба возвращают тот же результат, что и 3
. Теперь я попытался сделать то же самое с ключом, который не является частью хэш-карты, приведя целое число к HashKey
и вызвав для него два вышеуказанных метода:
cout << hm.value(static_cast<HashKey>(100)).x << endl;
cout << hm.find(static_cast<HashKey>(100)).value().x << endl;
Я получил 8
(за первый звонок с value().x
) и 5
(за второй звонок с find(...).value().x
)
В документах указано, что
Если в хэше нет элемента с указанным ключом, эти функции возвращают значение по умолчанию.
Я перешел по ссылке для default-constructed value
и получил следующее:
[...] например, QVector автоматически инициализирует свои элементы значениями, созданными по умолчанию, а QMap::value() возвращает значение, созданное по умолчанию, если указанный ключ отсутствует на карте. Для большинства типов значений это просто означает, что значение создается с использованием конструктора по умолчанию (например, пустая строка для QString). Но для примитивных типов, таких как int и double, а также для типов указателей язык C++ не определяет никакой инициализации; в таких случаях контейнеры Qt автоматически инициализируют значение равным 0.
В моем случае это будет означать вызов HashValue()
. Однако тот факт, что я получаю разные результаты, мягко говоря, сбивает с толку. Я ожидаю получить тот же результат, хотя в документах не упоминается, что делает find(...)
, когда в качестве аргумента передается недопустимый ключ. Все, что он говорит, он находит первое вхождение этого ключа и возвращает итератор (очевидно, поскольку я вызываю value()
в вызове выше).
За цитируемым выше фрагментом документа следует (снова возвращаясь к документу для QHash
)
Если вы хотите проверить, содержит ли хэш конкретный ключ, используйте contains()
Я могу справиться с необходимостью вызывать contains()
каждый раз, когда я запрашиваю свою хеш-карту, хотя это означает выполнение двух вызовов функций — сначала для проверки наличия ключа, а затем для вызова value(...)
для получения фактического значения, если найдена действительная запись. Приведенный ниже вызов возвращает "Key 100 not found"
:
cout << (hm.contains(static_cast<HashKey>(100)) ? "Key 100 found" : "Key 100 not found") << endl;
Я ожидаю, что эта проверка будет выполнена внутри, но, очевидно, этого не происходит (моя догадка заключается в том, чтобы предотвратить некоторое влияние производительности на функции запросов этого контейнера).
Вопрос здесь в том, почему все это происходит и что на самом деле происходит под всем этим?
Вот проект и код для него:
HashTest.pro
QT += core
QT += gui
CONFIG += c++11
TARGET = HashTest
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
main.cpp
#include <QCoreApplication>
#include <QHash>
#include <iostream>
using namespace std;
enum HashKey {
K1 = 0,
K2 = 1,
K3 = 2,
K4 = 3,
K5 = 4
};
class HashValue {
public:
int x;
HashValue(int x) { this->x = x; }
HashValue() {}
};
int main(int argc, char *argv[])
{
QHash<HashKey, HashValue> hm;
hm.insert(K1, HashValue((int)K1));
hm.insert(K2, HashValue((int)K2));
hm.insert(K3, HashValue((int)K3));
hm.insert(K4, HashValue((int)K4));
hm.insert(K5, HashValue((int)K5));
cout << hm.value(K4).x << endl;
cout << hm.value(static_cast<HashKey>(100)).x << endl;
cout << hm.find(K4).value().x << endl;
cout << hm.find(static_cast<HashKey>(100)).value().x << endl;
cout << (hm.contains(static_cast<HashKey>(100)) ? "Key 100 found" : "Key 100 not found") << endl;
return a.exec();
}