stoi转换失败直接抛异常,不返回错误码;严格要求输入,不跳过前导空格,遇非法字符或溢出即抛std::invalid_argument或std::out_of_range。

stoi 转换失败时直接抛异常,别指望它返回错误码
stoi 是最简捷的转换方式,但它对输入极其严格:遇到首个非法字符就停,如果开头就是非数字(比如空格、字母、符号),直接抛 std::invalid_argument;如果数字超出了 int 范围,则抛 std::out_of_range。它不会跳过前导空格,也不会告诉你停在哪儿了。
常见错误现象:stoi(" 123") 报 invalid_argument;stoi("123abc") 返回 123(看似成功,但没提示截断);stoi("2147483648")(超出 INT_MAX)触发 out_of_range。
- 使用前务必用
try/catch包裹,不能只靠if判断 - 若需容忍前导空格,先调用
std::string::find_first_not_of(" \t\n\r")手动跳过 - 若需知道解析到哪个位置,改用
std::strtol(C 风格,带endptr输出)
stringstream 更灵活但默认不校验溢出,容易静默出错
std::stringstream 的优势是能链式读取、支持多种类型混读,且自动跳过前导空白。但它的 >> 操作符在整数溢出时不会抛异常,而是置位流状态 failbit,同时把变量留为未定义值(通常是 0 或旧值)——这非常危险,因为不检查 ss.fail() 就直接用结果,会引入隐蔽 bug。
示例:std::stringstream ss("99999999999999999999"); int x; ss >> x; 后 x 可能仍是 0,而 ss.fail() 为 true,但没人看这个标志。
- 每次用
>>后必须检查ss.fail()或ss.good() - 用完记得调用
ss.clear()重置状态,否则后续读取全失效 - 若要严格等价于
stoi行为(如拒绝尾随字符),需手动检查ss.peek() == EOF
真正健壮的转换得组合判断:范围 + 尾部 + 空白
生产环境里,仅“能转成数字”不够,还要确认:是否全字符都被消费?有没有溢出?是否允许前后空白?这些 stoi 和 stringstream 单独都做不到,得组合处理。
一个轻量方案是用 std::strtol:它返回 long,但提供 char** endptr 输出解析终点,还能通过 errno == ERANGE 捕获溢出,且自动跳过前导空白。
char* end; errno = 0; long val = std::strtol(s.c_str(), &end, 10);- 检查
end == s.c_str()(全空白)、*end != '\0'(尾部有非法字符)、errno == ERANGE(溢出) - 再判断
val是否在INT_MIN~INT_MAX内,最后转int
性能差异小,但 stoi 在短字符串上略快,stringstream 初始化开销明显
对单次转换,stoi 基本是纯函数调用,无对象构造;std::stringstream 每次都要构造缓冲区、设置 locale、管理状态位,实测在百万次循环中慢 2–3 倍。不过这点差异只在高频转换(如解析日志每行几十个字段)时才值得抠。
- 若只是偶尔转换用户输入,选哪个都行,优先选语义清晰的
stoi - 若已有一个复用的
stringstream对象(比如持续解析 CSV 行),继续用它更省 - 别为了“性能”强行避免异常——
stoi抛异常只在错误路径发生,正常路径无成本
实际写的时候,最容易被忽略的是尾随字符和溢出边界交叉验证。比如 "123\0abc" 这种带嵌入空字符的 string,stoi 会停在 \0,但 strtol 也会——得靠 endptr 和原始长度比对才能发现没吃完整个 buffer。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











