了解找不到密钥时 QHash 的作用
Understanding what QHash does when key not found
注意:您可以在本文末尾找到一个最小的工作示例post。
我正在使用 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;
两者return结果相同即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
)
文档指出
If there is no item with the specified key in the hash, these
functions return a default-constructed value.
我按照 link default-constructed value
得到了以下信息:
[...] for example, QVector automatically initializes its items with
default-constructed values, and QMap::value() returns a
default-constructed value if the specified key isn't in the map. For
most value types, this simply means that a value is created using the
default constructor (e.g. an empty string for QString). But for
primitive types like int and double, as well as for pointer types, the
C++ language doesn't specify any initialization; in those cases, Qt's
containers automatically initialize the value to 0.
在我的例子中,这意味着 HashValue()
调用。然而,我得到不同结果的事实至少可以说是令人费解的。尽管文档没有提及 find(...)
在将无效密钥作为参数传递时会做什么,但我希望得到相同的结果。它只是说它找到了那个键的第一次出现并且 returns 是一个迭代器(显然因为我在上面的调用中调用了 value()
)。
在上面引用的文档片段之后(再次回到 QHash
的文档)
If you want to check whether the hash contains a particular key, use
contains()
我可以处理每次查询哈希映射时必须调用 contains()
的问题,尽管这意味着进行两次函数调用 - 首先检查密钥是否存在,然后调用 value(...)
来获取找到有效条目时的实际值。下面调用 returns "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();
}
value()
函数基本上只是用于访问值而不是检查您是否有值。
它是一个 returns 值,无法表明该值是否为 "invalid"。因此,如果设计是建造一个,那么选择。 Qt 可以作为替代方案抛出异常,但由于多种原因(与 c++ 标准库的容器相同)这里没有这样做。顺便说一句。
其次:
您使用 find()
的方式有点不对。
使用 find
你可以检查键是否在列表中,如果不在,它指向散列的 end()
迭代器。
QHash< Key,Value >::const_iterator valueIt = hash.find(<something>)
if(valueIt == hash.end())
{ // not found. error handling etc.
}
Value value = valueIt.value();
这通常是 "standard" 检查密钥是否存在并在 Map/Hash/Set/... 中访问它的方法。
所以当你使用
find(...).value();
您可能会访问导致未定义行为的 end()
迭代器。
注意:您可以在本文末尾找到一个最小的工作示例post。
我正在使用 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;
两者return结果相同即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
)
文档指出
If there is no item with the specified key in the hash, these functions return a default-constructed value.
我按照 link default-constructed value
得到了以下信息:
[...] for example, QVector automatically initializes its items with default-constructed values, and QMap::value() returns a default-constructed value if the specified key isn't in the map. For most value types, this simply means that a value is created using the default constructor (e.g. an empty string for QString). But for primitive types like int and double, as well as for pointer types, the C++ language doesn't specify any initialization; in those cases, Qt's containers automatically initialize the value to 0.
在我的例子中,这意味着 HashValue()
调用。然而,我得到不同结果的事实至少可以说是令人费解的。尽管文档没有提及 find(...)
在将无效密钥作为参数传递时会做什么,但我希望得到相同的结果。它只是说它找到了那个键的第一次出现并且 returns 是一个迭代器(显然因为我在上面的调用中调用了 value()
)。
QHash
的文档)
If you want to check whether the hash contains a particular key, use contains()
我可以处理每次查询哈希映射时必须调用 contains()
的问题,尽管这意味着进行两次函数调用 - 首先检查密钥是否存在,然后调用 value(...)
来获取找到有效条目时的实际值。下面调用 returns "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();
}
value()
函数基本上只是用于访问值而不是检查您是否有值。
它是一个 returns 值,无法表明该值是否为 "invalid"。因此,如果设计是建造一个,那么选择。 Qt 可以作为替代方案抛出异常,但由于多种原因(与 c++ 标准库的容器相同)这里没有这样做。顺便说一句。
其次:
您使用 find()
的方式有点不对。
使用 find
你可以检查键是否在列表中,如果不在,它指向散列的 end()
迭代器。
QHash< Key,Value >::const_iterator valueIt = hash.find(<something>)
if(valueIt == hash.end())
{ // not found. error handling etc.
}
Value value = valueIt.value();
这通常是 "standard" 检查密钥是否存在并在 Map/Hash/Set/... 中访问它的方法。
所以当你使用
find(...).value();
您可能会访问导致未定义行为的 end()
迭代器。