了解未找到密钥时QHash的作用

时间:2016-10-11 08:38:00

标签: c++ qt hash key qhash

注意:您可以在本文末尾找到最小的工作示例。

我使用 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

我按照default-constructed value的链接获得了以下内容:

  例如,

[...],QVector会自动初始化其项目   默认构造的值,QMap :: value()返回一个   如果指定的键不在地图中,则为default-construct值。对于   大多数值类型,这只是意味着使用。创建一个值   默认构造函数(例如,QString的空字符串)。但对于   原始类型,如int和double,以及指针类型,   C ++语言没有指定任何初始化;在那些情况下,Qt's   容器自动将值初始化为0。

在我的情况下,这意味着HashValue()电话。然而,我得到不同结果的事实至少可以说是令人费解。我希望得到相同的结果,虽然文档没有提到当无效密钥作为参数传递时find(...)做什么。所有它说它找到第一次出现的那个键并返回一个迭代器(显然,因为我在上面的调用中调用了value())。

通过上面引用的文档片段(再次回到QHash的文档)

  

如果要检查哈希是否包含特定键,请使用   含有()

我可以处理每次查询哈希映射时都必须调用contains()这虽然这意味着进行两次函数调用 - 首先检查密钥是否存在然后调用value(...)来获取实际值如果找到有效条目,则为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();
}

1 个答案:

答案 0 :(得分:6)

value()函数基本上只是用于访问值,而不是检查是否有一个值。

它返回一个值,并且无法指示该值是否为&#34;无效&#34;或不。所以选择设计是否构建一个。 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();

这通常是&#34;标准&#34;检查密钥是否存在的方法,并在Map / Hash / Set / ....

中访问它

所以当你使用

find(...).value();

您可能会访问导致未定义行为的end()迭代器。