You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++自定义类存入unordered_set触发段错误问题求助

问题:HexagonField类插入std::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这类工具函数不需要依赖当前实例的状态,应该改为静态成员函数,避免误用。

修复步骤:

  1. 将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)
      };
      
  2. 将工具类成员函数改为静态函数
    像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文件中的函数体无需修改,保持原有逻辑即可。
  3. 补充析构函数实现
    头文件中声明了~HexagonField();但未实现,需在hexagonField.cpp中补充:

    HexagonField::~HexagonField() = default;
    
  4. 优化哈希函数(可选但推荐)
    当前哈希函数仅使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:15:17