使用unordered_multimap存储自定义nod结构体的问题排查与实现指导
你的核心逻辑(让节点自身插入哈希表)是可行的,但代码里有几个关键问题导致Init函数无法正常工作,咱们一步步拆解并修正:
1. 最直接的问题:类型不匹配
你的theExplored定义是std::unordered_multimap<int, nod>,也就是容器的值类型是nod对象本身;但在nod::Init()里你插入的是{ pathManhattan + depth, this }——this是nod*(指向当前nod对象的指针),两者类型完全不兼容,编译器肯定会报错。
两种修正方向:
- 如果你想存储指向节点的指针(更推荐,避免拷贝大对象,同时保留节点间的引用关系):
把容器定义改成指针类型:
此时std::unordered_multimap<int, nod*> theExplored; std::unordered_multimap<int, nod*> theFrontier;Init函数的插入代码就能正常工作了:void nod::Init() { theExplored.insert({ pathManhattan + depth, this }); } - 如果你一定要存储节点对象:
那插入时需要传入对象本身,而不是指针:
但要注意:nod结构体里有void nod::Init() { theExplored.insert({ pathManhattan + depth, *this }); }nodParinte指针成员,默认拷贝构造会做浅拷贝,多个容器元素会共享同一个父节点指针,容易引发悬空指针问题,不推荐这种方式。
2. 致命的编译问题:循环包含
你的Nod.cpp里写了#include "ConsoleApplication1.cpp",这会形成循环依赖:ConsoleApplication1.cpp已经包含了Nod.h,Nod.cpp又反过来包含ConsoleApplication1.cpp,最终会导致全局变量theExplored和theFrontier被重复定义,编译直接失败。
解决方法:
永远不要包含.cpp文件,只包含头文件。删除Nod.cpp里的#include "ConsoleApplication1.cpp",然后在Nod.h里对全局容器做前向声明,让nod类知道容器的存在:
// Nod.h 开头 #include <unordered_multimap> // 前向声明全局容器 extern std::unordered_multimap<int, nod*> theExplored;
然后在ConsoleApplication1.cpp里正常定义这些全局容器即可。
3. 可选优化:避免全局变量(提升代码可维护性)
全局变量虽然简单,但在大型项目里容易引发代码耦合问题。你可以把容器作为参数传给Init函数,让nod类不依赖全局变量:
// Nod.h 里修改Init函数声明 void Init(std::unordered_multimap<int, nod*>& container); // Nod.cpp 里实现 void nod::Init(std::unordered_multimap<int, nod*>& container) { container.insert({ pathManhattan + depth, this }); } // main函数里调用 int main() { nod myNode; myNode.pathManhattan = 3; myNode.depth = 1; myNode.Init(theExplored); return 0; }
修正后的完整代码示例
Nod.h
#pragma once #include <iostream> #include <unordered_multimap> // 前向声明全局容器 extern std::unordered_multimap<int, nod*> theExplored; struct nod { int stare[100], pathManhattan, depth; nod* nodParinte; char actiune; nod(); void Citire(int n); void Init(); };
Nod.cpp
#include "Nod.h" // 用初始化列表替代构造函数内赋值,更规范 nod::nod() : pathManhattan(0), depth(0), nodParinte(nullptr), actiune('\0') {} void nod::Citire(int n) { for (int i = 0; i < n*n; i++) { std::cin >> stare[i]; } } void nod::Init() { theExplored.insert({ pathManhattan + depth, this }); }
ConsoleApplication1.cpp
#include <iostream> #include <unordered_multimap> #include "Nod.h" // 定义全局容器 std::unordered_multimap<int, nod*> theExplored; std::unordered_multimap<int, nod*> theFrontier; int main() { nod testNode; testNode.pathManhattan = 5; testNode.depth = 2; testNode.Init(); // 验证插入结果 for (const auto& pair : theExplored) { std::cout << "键值:" << pair.first << ",节点深度:" << pair.second->depth << std::endl; } return 0; }
总结
你的核心思路(让节点自身插入哈希表)是正确的,只是在容器类型匹配和编译依赖上犯了基础错误。修正这两个问题后,代码就能正常运行了。如果追求更健壮的代码,建议使用智能指针(比如std::shared_ptr<nod>)管理节点生命周期,进一步避免内存泄漏风险。
内容的提问来源于stack exchange,提问作者user14399919

