了解找不到密钥时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的链接,得到了以下内容:

[…例如,QVector自动初始化它的项默认构造的值,QMap::value()返回a如果指定的键不在映射中,则默认构造的值。为对于大多数值类型,这仅仅意味着使用默认构造函数(例如QString的空字符串)。但对于int和double等基本类型,以及指针类型c++语言没有指定任何初始化;在这些情况下,Qt's容器自动将该值初始化为0。

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

上面引用的文档片段后面是

(再次回到QHash的文档中)

如果要检查散列是否包含特定键,请使用包含()

我可以处理每次查询哈希映射时必须调用contains(),尽管这意味着进行两个函数调用-首先检查是否存在key,然后调用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();
}

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

它返回一个值,没有办法表明该值是否"无效"。所以选择如果设计是建造一个。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();

这通常是检查键是否存在并在Map/Hash/Set/....中访问它的"标准"方法

所以当你使用

find(...).value();

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

相关内容

  • 没有找到相关文章

最新更新