必须先检查栈大小≥2再弹出操作数,因rpn遇运算符需弹出右操作数b和左操作数a,空栈或元素不足时top()/pop()行为未定义,易崩溃;同时须校验除零、溢出及负数合法性和token分割鲁棒性。

遇到 std::stack 空栈弹出就崩溃?先检查操作数是否够两个
逆波兰表达式(RPN)求值本质是栈模拟:每读到数字就压栈,读到运算符就弹出两个操作数——注意顺序:**先弹的是右操作数,后弹的是左操作数**。常见崩溃源于没校验栈大小,比如对单个数或空表达式执行 pop()。
实操建议:
- 每次遇到运算符前,用
stack.size() 判断是否足够弹出两个数,不够直接报错或返回异常值 - 字符串分割时小心空格和连续分隔符,推荐用
std::istringstream或按空格切分后过滤空字符串 - 数字转换别硬写
atoi,用std::stoi并捕获std::invalid_argument异常
std::stoi 解析负数失败?确保 token 不含前后空格和符号混淆
负数如 "-5" 能被 std::stoi 正确识别,但若 token 实际是 " -5"(带前导空格)或 "- 5"(符号与数字分离),就会抛异常或解析为 0。
使用场景中容易忽略的点:
- 用
std::istringstream分词时,>>操作符自动跳过空白,更安全;手写split()时务必trim()每个 token - 不要假设所有负数都以
'-'开头且后面紧跟数字——要排除减号运算符干扰,这靠的是 token 序列位置:只有在数字该出现的位置(即非运算符上下文)才解析为负数 - 如果输入含浮点数,
std::stoi会截断,此时应改用std::stod并统一用double栈
除零、溢出不报错?必须手动检查运算符行为边界
C++ 默认不会为整数除零或溢出抛异常,a / 0 是未定义行为,INT_MAX + 1 会静默回绕。RPN 求值器必须主动防御。
关键检查点:
- 对
'/'和'%',判断右操作数是否为 0,是则返回错误码或抛std::runtime_error("division by zero") - 加减乘前做溢出预检:例如乘法可用
if (b != 0 && a > INT_MAX / b)类似逻辑(注意符号组合),或直接用std::numeric_limits<int>::max()</int>辅助判断 - 若业务允许,改用
long long扩大中间计算范围,比实时检测更简单可靠
为什么用 std::stack<int></int> 而不用 std::vector?性能与语义都要
虽然 std::vector 也能模拟栈(push_back/pop_back),但 std::stack 更合适:
- 接口明确限制为 LIFO 操作,避免误用
operator[]或迭代器破坏栈结构 - 底层容器默认是
std::deque,在头部/尾部插入删除都是 O(1),比std::vector的尾部扩容更稳定 - 若真有性能敏感场景(如百万级 token),可显式指定
std::stack<int std::vector>></int>避免 deque 分配开销,但多数情况没必要
真正容易被忽略的是:运算符优先级在 RPN 中已由顺序消除,所以不需要任何优先级表或递归下降——只要老老实实按 token 顺序处理栈,就不可能算错。复杂点全在输入校验和边界处理上。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











