C++编译器语义分析中vector元素find操作后数据损坏问题求助
你遇到的数据损坏问题核心原因非常明确——在处理函数声明的Visit方法里,你犯了一个C++新手常踩的坑:把局部变量的地址存入了全局/类成员的functionList中:
AST::FunctionDeclare newNode = p_node; functionList->push_back(&newNode);
当这个Visit函数执行完毕时,栈上的局部变量newNode会被立即销毁,对应的内存地址会被操作系统回收或重新分配给其他数据。之后你在处理函数调用时遍历functionList访问这些指针,本质上是在访问已经失效的内存——这就是典型的**悬空指针(野指针)**问题,和find()操作本身完全无关,find()没修改你的数据,但你访问的内存已经不属于你了。
根据你的场景,有几种可靠的修复方案:
1. 直接存储原AST节点的指针(最简便)
如果传入的p_node(AST函数声明节点)在整个编译过程中都会存在(比如AST树是在堆上构建的,直到编译结束才销毁),那你根本不需要复制节点,直接把原节点的地址存入functionList:
// 去掉多余的局部变量newNode,直接存原节点指针 functionList->push_back(&p_node);
这个方案零额外成本,但前提是要确保原AST节点的生命周期覆盖functionList的整个使用周期。
2. 在堆上创建节点副本(手动管理内存)
如果原节点的生命周期无法保证,或者你需要独立的函数节点副本,那就用new在堆上分配内存,再把指针存入列表:
// 在堆上创建函数节点副本,所有权转移给functionList AST::FunctionDeclare* newNode = new AST::FunctionDeclare(p_node); functionList->push_back(newNode);
注意:这种方式需要在编译流程结束后,手动遍历functionList调用delete释放每个节点的内存,避免内存泄漏。
3. 使用智能指针自动管理内存(最安全)
为了避免手动管理内存的麻烦,推荐用C++的智能指针来存储函数节点。比如把functionList的类型从std::vector<AST::FunctionDeclare*>改成std::vector<std::unique_ptr<AST::FunctionDeclare>>(如果不需要共享节点所有权),然后:
// 用make_unique在堆上创建副本,智能指针会自动管理内存 functionList->push_back(std::make_unique<AST::FunctionDeclare>(p_node));
这样当functionList被销毁时,所有智能指针会自动释放对应的堆内存,既不会有野指针问题,也不用担心内存泄漏。
你现在在处理函数调用时,遍历整个functionList查找目标函数,时间复杂度是O(n)。可以维护一个std::unordered_map<std::string, AST::FunctionDeclare*>(或对应智能指针版本),把函数名直接映射到节点指针,这样查找效率会提升到O(1):
// 定义一个类成员或全局的函数映射表 std::unordered_map<std::string, AST::FunctionDeclare*> functionMap; // 在处理函数声明时存入映射表 functionMap[p_node.getName()] = &p_node; // 或堆上的节点指针 // 在处理函数调用时直接查找 auto it = functionMap.find(p_node.getName()); if (it == functionMap.end()) { std::string errorText = "No function with name '" + p_node.getName() + "' was found."; Error(errorText); return; } AST::FunctionDeclare* pFunc = it->second; // 后续处理逻辑
内容的提问来源于stack exchange,提问作者Luponius

