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

使用自定义类作为unordered_map键的问题及构造函数相关疑问

问题分析与解决

一、为什么你的unordered_map配置无法运行?

你遇到的报错有两个核心原因:

1. 遍历时代码未指定完整的模板参数

你在遍历originalToCopy时写了:

for (unordered_map<RandomListNode, RandomListNode>::value_type value : originalToCopy) { ... }

这里的unordered_map<RandomListNode, RandomListNode>没有指定你自定义的MyHash和KeyEqual模板参数,编译器会尝试实例化默认的std::hash<RandomListNode>和std::equal_to<RandomListNode>——但标准库没有为自定义结构体提供默认哈希函数,因此触发报错。

你自己发现的修正写法是对的,但更简洁且不易出错的方式是用auto推导:

for (auto& value : originalToCopy) { ... }

这样编译器会自动匹配originalToCopy的完整模板类型,避免手动写错。

2. 错误地将RandomListNode对象作为键(而非指针)

这是更关键的问题:你的哈希函数MyHash用了&node(对象的内存地址),相等判断KeyEqual也依赖对象地址,但unordered_map存储键时会拷贝你的RandomListNode对象。这意味着:

  • 存入map的键对象和你原始节点的地址完全不同,你的哈希/相等逻辑彻底失效;
  • 即使你用原始节点去查询map,也会因为地址不匹配找不到对应条目。

针对复制带随机指针的链表场景,正确的做法是用指针作为键:

// 不需要自定义哈希和相等函数,标准库支持指针的默认哈希与比较
unordered_map<RandomListNode*, RandomListNode*> originalToCopy;

这样哈希函数默认使用指针的地址,相等判断默认比较指针值,完全符合你的需求(映射原始节点指针到拷贝节点指针)。


二、关于无默认/拷贝/移动构造函数的类的疑问

如果RandomListNode确实无法修改,且没有默认构造、拷贝构造或移动构造函数:

1. operator[]绝对无法使用

unordered_map::operator[]的核心逻辑是:当键不存在时,会默认构造一个键的实例并插入到map中,因此它要求键类型必须具备默认构造函数。如果你的类没有默认构造,调用operator[]会直接编译报错。

2. emplace()的可用性取决于具体情况

emplace()的作用是在map内部直接构造键值对,不需要先构造好对象再拷贝/移动进去,但它有前提:

  • 你必须能传递足够的参数,让map在原地构造pair<const Key, T>;
  • 如果键类型没有拷贝/移动构造函数,那么构造键时必须完全依赖原地构造(即通过完美转发参数调用键的构造函数)。

但回到你的场景,如果你坚持用RandomListNode对象作为键(不推荐),而该类只有带int的构造函数且无拷贝/移动构造,你可以尝试用piecewise_construct来原地构造键值对:

originalToCopy.emplace(
    std::piecewise_construct,
    std::forward_as_tuple(10),  // 传递给RandomListNode构造函数的参数(键)
    std::forward_as_tuple(10)   // 传递给RandomListNode构造函数的参数(值)
);

但仍然要提醒:这种做法会导致键对象和原始节点地址不同,你的哈希/相等逻辑还是失效的,所以用指针作为键才是正确的选择。

内容的提问来源于stack exchange,提问作者pwh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:15:50