带有自声明散列函数的segfault



ChunkCorner.h

#pragma once
#include <filesystem>
#include <iostream>
class ChunkCorner
{
public:
int x;
int y;
std::filesystem::path to_filename();
};
size_t hf(const ChunkCorner &chunk_corner);
bool eq(const ChunkCorner &c1, const ChunkCorner &c2);

ChunkCorner.cpp:fwiw:hf和eq函数的实现是基于C++书第917页。

#include "ChunkCorner.h"
using namespace std;
size_t hf(const ChunkCorner &chunk_corner)
{
return hash<int>()(chunk_corner.x) ^ hash<int>()(chunk_corner.y);
}
bool eq(const ChunkCorner &c1, const ChunkCorner &c2)
{
return c1.x == c2.x && c1.y == c2.y;
}
[...]

在另一段代码中,我使用如下类:

unordered_set<ChunkCorner, decltype(&hf), decltype(&eq)> chunks_to_load {};
ChunkCorner c {1,2};
chunks_to_load.insert(c);

在insert调用中,我得到一个segfault(使用断点确定)。

我使用VS代码,当我在调试模式下启动程序时,它会跳到hashtable_policy.h:中segfault上的以下位

__hash_code
_M_hash_code(const _Key& __k) const
{
static_assert(__is_invocable<const _H1&, const _Key&>{},
"hash function must be invocable with an argument of key type");
return _M_h1()(__k);
}

我是C++的新手,很难理解问题所在,也不知道如何进行调试。。。

您需要将hash和equals函数传递给构造函数。你已经在类型参数中声明了它们的类型,这将是一个指向函数的指针,但你还没有传递它们。所以它们很可能是零初始化的,所以nullptr。正确使用它们应该这样做:

unordered_set<ChunkCorner, decltype(&hf), decltype(&eq)> chunks_to_load {16, hf, eq};

但是,我建议您将Hash/Equals函数重写为函数对象。这样,默认操作将正常工作。

struct MyHasher {
size_t operator()(const ChunkCorner &chunk_corner) const
{
return hash<int>()(chunk_corner.x) ^ hash<int>()(chunk_corner.y);
}
};
struct MyEq {
bool operator()(const ChunkCorner &c1, const ChunkCorner &c2) const
{
return c1.x == c2.x && c1.y == c2.y;
}
};

最新更新