C++ std::map键值对二次调用函数后丢失问题求助
你遇到的问题核心是错误地传递了要赋值的目标变量名,再加上std::map的operator[]特性导致了键值对的“丢失”(其实是根本没存到正确的键上)。让我一步步拆解问题:
1. 关键错误:目标变量名传递错误
在convertToPostFixAndPrint函数中,你传递给romanCalc的infixVector是表达式部分的tokens(也就是assignmentStatement从第3个元素开始的内容),比如第一次调用时infixVector是[XII],这是罗马数字token,不是变量名b。但你在romanCalc里却用infixVector[0]->variable()来获取要赋值的变量名——罗马数字token的variable()方法返回的肯定不是b(要么是未定义的垃圾值,要么是空字符),这就导致你把计算结果存到了一个错误的键上,而真正的变量b从未被存入symTable。
2. 次要错误:std::map::operator[]的“隐式插入”特性
当你在处理变量b时,使用了symTable[roman->variable()]——如果symTable里没有这个键,operator[]会自动插入一个默认值(int的默认值是0),然后返回这个值。这就是为什么你看到“Value retrieved from b is 0”:因为b根本不在symTable里,是你用operator[]的时候自动加进去的,值为0。
修正方案
步骤1:传递正确的目标变量名给romanCalc
修改convertToPostFixAndPrint中调用romanCalc的代码,把真正的目标变量名(也就是assignmentStatement[0]对应的变量)传进去:
// 在convertToPostFixAndPrint函数里,替换原来的romanCalc调用 char targetVariable = assignmentStatement[0]->variable(); romanCalc(postfixTokens, targetVariable, symTable);
步骤2:修改romanCalc的函数签名和逻辑
更新romanCalc的参数,去掉无用的infixVector,改用传入的targetVariable,同时修正变量查找逻辑:
void romanCalc(const std::vector<Token *> &postfixVector, char targetVar, std::map<char, int> &symTable) { std::stack<int> romanStack; for(auto roman: postfixVector) { if(roman->isValidRomanNumeral()) { RomanNumeral * romans = new RomanNumeral(roman->romanNumber()); romanStack.push(romans->convertRomanToInt()); delete romans; // 别忘了释放内存,避免内存泄漏! } else if(roman->isAVariable()) { char var = roman->variable(); std::cout << "Variable: " << var << std::endl; // 先查找,避免operator[]隐式插入 auto it = symTable.find(var); if(it != symTable.end()){ std::cout << "Value retrieved from " << var << " is " << it->second << std::endl; romanStack.push(it->second); } else { std::cout << "Error: Undefined variable '" << var << "'" << std::endl; exit(1); } } else { // 运算符处理逻辑保持不变,但新增栈空检查避免崩溃 if(romanStack.size() < 2) { std::cout << "Error: Insufficient operands for operator" << std::endl; exit(1); } int second = romanStack.top(); romanStack.pop(); std::cout << second << " second\n"; int first = romanStack.top(); romanStack.pop(); std::cout << first << " first\n"; if(roman->isAdditionOperator()) romanStack.push(first + second); else if(roman->isSubtractionOperator()) romanStack.push(first - second); else if(roman->isMultiplicationOperator()) romanStack.push(first * second); else if(roman->isDivisionOperator()) romanStack.push(first / second); else if(roman->isModuloOperator()) romanStack.push(first % second); else { std::cout << "Expected an arithmetic operator instead found the following token \n"; roman->print(); exit(1); } } } // 把计算结果存入正确的目标变量 symTable[targetVar] = romanStack.top(); std::cout << "Testing Retrieve from map: " << symTable[targetVar] << std::endl; std::cout << romanStack.top() << std::endl; }
步骤3:额外优化:避免内存泄漏
注意你在原代码里用了new RomanNumeral(...)但没有delete,这会导致内存泄漏,上面的修正代码里已经加上了delete romans;来释放内存。
修正后的效果
第一次调用时,symTable['b']会被正确赋值为12;第二次调用处理c = MMDCCCLXXXVIII + b时,查找b会直接找到已存在的键,取出值12参与计算,最终symTable['c']会被设置为正确的结果(2888 + 12 = 2900)。
内容的提问来源于stack exchange,提问作者Debug

