C++自定义类存入unordered_set触发段错误问题求助
我正在学习游戏六边形地图开发教程,原教程用struct实现六边形字段,我改成HexagonField类后编译正常,但调用std::unordered_set的insert方法插入实例时触发段错误,怀疑哈希函数有误,找不到排查方向,求解决。
main.c
#include <unordered_set> #include "hexagonField.hpp" int main(int argc, char **argv) { std::unordered_set <HexagonField> map; map.insert(HexagonField(0, 0, 0)); return 0; }
hexagonField.hpp
#ifndef HEXAGON_H #define HEXAGON_H #include <assert.h> #include <vector> class HexagonField { public: const int q, r, s; HexagonField(int q, int r, int s); ~HexagonField(); HexagonField hexagonAdd(HexagonField a, HexagonField b); HexagonField hexagonSubtract(HexagonField a, HexagonField b); HexagonField hexagonMultiply(HexagonField a, int k); int hexagonLength(HexagonField hex); int hexagonDistance(HexagonField a, HexagonField b); HexagonField hexagonDirection(int direction /* 0 to 5 */); HexagonField hexagonNeighbor(HexagonField hex, int direction); const std::vector<HexagonField> hexagonDirections = { HexagonField(1, 0, -1), HexagonField(1, -1, 0), HexagonField(0, -1, 1), HexagonField(-1, 0, 1), HexagonField(-1, 1, 0), HexagonField(0, 1, -1) }; bool operator == (const HexagonField comparedHex) const { return this->q == comparedHex.q && this->r == comparedHex.r && this->s == comparedHex.s; } bool operator != (const HexagonField comparedHex) const { return !(*this == comparedHex); }; }; namespace std { template<> struct hash<HexagonField> { size_t operator()(const HexagonField & obj) const { return hash<int>()(obj.q); } }; } #endif
hexagonField.cpp
#include "hexagonField.hpp" HexagonField::HexagonField(int q, int r, int s): q(q), r(r), s(s) { assert (q + r + s == 0); } HexagonField HexagonField::hexagonAdd(HexagonField a, HexagonField b) { return HexagonField(a.q + b.q, a.r + b.r, a.s + b.s); } HexagonField HexagonField::hexagonSubtract(HexagonField a, HexagonField b) { return HexagonField(a.q - b.q, a.r - b.r, a.s - b.s); } HexagonField HexagonField::hexagonMultiply(HexagonField a, int k) { return HexagonField(a.q * k, a.r * k, a.s * k); } int HexagonField::hexagonLength(HexagonField hex) { return int((abs(hex.q) + abs(hex.r) + abs(hex.s)) / 2); } int HexagonField::hexagonDistance(HexagonField a, HexagonField b) { return hexagonLength( hexagonSubtract(a, b)); } HexagonField HexagonField::hexagonDirection(int direction /* 0 to 5 */) { assert (0 <= direction && direction < 6); return hexagonDirections[direction]; } HexagonField HexagonField::hexagonNeighbor(HexagonField hex, int direction) { return hexagonAdd(hex, hexagonDirection(direction)); }
核心问题:无限递归构造导致栈溢出
段错误的根源不是哈希函数,而是类中的hexagonDirections被定义为非静态成员变量。每个HexagonField实例构造时,都会初始化这个vector,而vector中的6个HexagonField元素又会各自构造自己的hexagonDirections,形成无限递归构造,最终导致栈溢出触发段错误。
另外,当前的成员函数设计也不合理:比如hexagonAdd、hexagonDirection这类工具函数不需要依赖当前实例的状态,应该改为静态成员函数,避免误用。
修复步骤:
将
hexagonDirections改为静态成员变量
在头文件中声明为static,并在cpp文件中定义初始化,确保所有实例共享一份:- 修改
hexagonField.hpp中的声明:class HexagonField { public: // ... 其他成员 ... static const std::vector<HexagonField> hexagonDirections; // ... 其他成员 ... }; - 在
hexagonField.cpp中添加定义:const std::vector<HexagonField> HexagonField::hexagonDirections = { HexagonField(1, 0, -1), HexagonField(1, -1, 0), HexagonField(0, -1, 1), HexagonField(-1, 0, 1), HexagonField(-1, 1, 0), HexagonField(0, 1, -1) };
- 修改
将工具类成员函数改为静态函数
像hexagonAdd、hexagonDirection这类不需要访问当前实例的函数,声明为static:- 修改
hexagonField.hpp中的函数声明:static HexagonField hexagonAdd(HexagonField a, HexagonField b); static HexagonField hexagonSubtract(HexagonField a, HexagonField b); static HexagonField hexagonMultiply(HexagonField a, int k); static int hexagonLength(HexagonField hex); static int hexagonDistance(HexagonField a, HexagonField b); static HexagonField hexagonDirection(int direction /* 0 to 5 */); static HexagonField hexagonNeighbor(HexagonField hex, int direction); - cpp文件中的函数体无需修改,保持原有逻辑即可。
- 修改
补充析构函数实现
头文件中声明了~HexagonField();但未实现,需在hexagonField.cpp中补充:HexagonField::~HexagonField() = default;优化哈希函数(可选但推荐)
当前哈希函数仅使用q字段会导致大量冲突,可结合三个字段生成更均匀的哈希值:namespace std { template<> struct hash<HexagonField> { size_t operator()(const HexagonField & obj) const { size_t h1 = hash<int>()(obj.q); size_t h2 = hash<int>()(obj.r); size_t h3 = hash<int>()(obj.s); return h1 ^ (h2 << 1) ^ (h3 << 2); } }; }
验证
完成以上修改后重新编译运行,map.insert(HexagonField(0,0,0))将正常执行,不会触发段错误。
内容的提问来源于stack exchange,提问作者Desfell

