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

使用std::tuple<int*,int*>为自定义键的unordered_map中vector内容丢失

问题:自定义哈希映射使用指针键导致访问异常

我需要实现一个哈希映射,输入为两个3D坐标数组(int start[3]、int stop[3]),输出为std::vector<int>。为此我将std::tuple<int*, int*>定义为自定义类型CoordsKey,并重写operator(),基于坐标值创建std::tuple<int, int, int, int, int, int>,借助Boost计算哈希值。

测试时发现:在test()函数内,使用局部定义的坐标数组作为键,向map中添加vector并修改,此时vector大小为2;但返回main()函数后,用相同坐标值的局部数组作为键访问map,得到的vector内容丢失,大小为0。尽管两次访问的哈希值完全相同,但问题依然存在。而使用int作为键时,程序运行正常。

请问为何第一个程序失效,我的错误是什么?


解答

核心错误在于你用指针作为哈希键的组成部分,但哈希映射的键相等判断逻辑是比较指针地址,而非指针指向的内容,具体原因如下:

  1. 键的相等判断逻辑不符合预期
    你定义的CoordsKey是std::tuple<int*, int*>,对于std::unordered_map这类哈希容器,判断两个键是否相等时,默认使用std::tuple的operator==——它会直接比较两个指针的内存地址,而不是去对比指针指向的6个坐标值。
    test()函数里的局部数组和main()里的局部数组是完全独立的栈内存对象,地址必然不同,所以哪怕它们的坐标值完全一致,哈希容器也会把这两个CoordsKey判定为不同的键。

  2. 哈希值相同不代表键相等
    你看到两次哈希值相同只是发生了哈希碰撞,哈希容器在发现哈希值相同时,会进一步用operator==验证键是否真的相等。由于指针地址不同,验证不通过,容器会创建一个新的空std::vector<int>条目,而非返回你之前在test()中存储的那个。

  3. 用int作为键正常的原因
    当键是int时,容器的相等判断是基于int的值比较,相同数值会被判定为同一个键,所以能正常访问到对应的存储内容。

修复方案

  • 方案一(推荐):直接用值类型作为键
    放弃指针封装,直接用存储坐标值的类型作为键,比如std::tuple<int, int, int, int, int, int>,这样哈希计算和相等判断都会基于坐标值,完全符合你的需求。

  • 方案二:自定义相等比较器
    如果必须保留CoordsKey的指针封装,需要给哈希容器指定自定义的相等比较器,让它对比指针指向的坐标值而非地址:

    struct CoordsEqual {
        bool operator()(const CoordsKey& a, const CoordsKey& b) const {
            // 比较两个指针指向的6个int值是否全部相等
            return std::memcmp(std::get<0>(a), std::get<0>(b), 3*sizeof(int)) == 0
                && std::memcmp(std::get<1>(a), std::get<1>(b), 3*sizeof(int)) == 0;
        }
    };
    
    // 使用时指定比较器
    std::unordered_map<CoordsKey, std::vector<int>, YourHashFunc, CoordsEqual> your_map;
    

内容的提问来源于stack exchange,提问作者比尔盖子

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:35:39