rba*_*dar 2 c++ hash qt key qhash
注意:您可以在本文末尾找到一个最小的工作示例.
我正在使用Qt 5.7.假设我有以下内容QHash:
QHash<HashKey, HashValue> hm;
Run Code Online (Sandbox Code Playgroud)
同
enum HashKey {
K1,
K2,
K3,
K4,
K5
}
Run Code Online (Sandbox Code Playgroud)
和
class HashValue {
public:
int x;
HashValue(int x) {
this->x = x;
}
}
Run Code Online (Sandbox Code Playgroud)
我已经像这样初始化了哈希映射:
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));
Run Code Online (Sandbox Code Playgroud)
我通过电话测试了它
cout << hm.value(K4).x << endl;
cout << hm.find(K4).value().x << endl;
Run Code Online (Sandbox Code Playgroud)
两者都返回相同的结果3.现在我尝试使用一个不是哈希映射的一部分的键来做同样的操作,方法是将一个整数转换为HashKey并调用上面两个方法:
cout << hm.value(static_cast<HashKey>(100)).x << endl;
cout << hm.find(static_cast<HashKey>(100)).value().x << endl;
Run Code Online (Sandbox Code Playgroud)
我得到的是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;
Run Code Online (Sandbox Code Playgroud)
我希望这个检查是在内部完成的,但显然这不会发生(我的猜测是防止对这个容器的查询功能产生一些性能影响).
这里的问题是为什么所有这一切都发生了,实际上发生了什么呢?
这是项目及其代码:
HashTest.pro
QT += core
QT += gui
CONFIG += c++11
TARGET = HashTest
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
该value()函数基本上只是用于访问值,而不是检查是否有一个值.
它返回一个值,无法指示该值是否为"无效".所以选择设计是否构建一个.Qt可以作为一个替代方案抛出一个异常,但由于几个原因(这与c ++标准库btw的容器相同),这里没有这样做.
其次:
你有点用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();
Run Code Online (Sandbox Code Playgroud)
这通常是检查密钥是否存在并在Map/Hash/Set /中访问它的"标准"方法.
所以当你使用
find(...).value();
Run Code Online (Sandbox Code Playgroud)
您可能会访问end()导致未定义行为的迭代器.