std::stoi最常用但非法输入抛异常致崩溃;std::from_chars无异常、高性能但不跳空白;atoi无错误反馈且空指针导致未定义行为;处理空格需手动trim或用stringstream。

std::stoi 用法与常见崩溃原因
直接调用 std::stoi 是最常用的方式,但它在输入非法时会抛出 std::invalid_argument 或 std::out_of_range 异常,不加捕获会导致程序终止。
- 空字符串、纯空白、非数字前缀(如
"abc123")触发std::invalid_argument - 超出
int表示范围(如"2147483648")触发std::out_of_range - 它默认按十进制解析,不支持前导
0x或0自动识别进制
try {
int x = std::stoi("123");
} catch (const std::invalid_argument&) {
// 处理非数字内容
} catch (const std::out_of_range&) {
// 处理溢出
}
std::from_chars 避免异常且性能更高
std::from_chars 是 C++17 引入的无异常、零分配方案,适合高频或性能敏感场景。它返回一个 std::from_chars_result 结构体,需手动检查结果。
- 不抛异常,仅通过
ec(error code)和ptr(解析结束位置)判断成败 - 支持指定进制,例如
std::from_chars(s.data(), s.data() + s.size(), value, 10) - 跳过前导空白?不支持 —— 它严格从首字符开始,
" 123"会被判为失败
std::string s = "456";
int value;
auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value);
if (ec == std::errc()) {
// 解析成功,value 已赋值
} else if (ec == std::errc::invalid_argument) {
// 无有效数字
} else if (ec == std::errc::result_out_of_range) {
// 溢出
}
atoi 不推荐用于新代码
atoi 来自 C 标准库,行为简单粗暴:遇到非法字符就停止并返回 0,无法区分 "0"、""、"abc" 这三者。没有错误反馈机制,极易引入隐蔽 bug。
- 传入空指针直接未定义行为(通常 crash)
- 不检查溢出,超范围时结果是实现定义的(常见为
INT_MAX或INT_MIN) - 不能指定进制,始终按十进制解析
// 危险示例:以下三者都返回 0,但含义完全不同
atoi(""); // 0 —— 空串
atoi("0"); // 0 —— 合法零
atoi("xyz"); // 0 —— 完全非法
处理带空格或前后缀的 string
如果原始 std::string 可能含前导/尾随空白(如用户输入、文件读取),std::stoi 和 std::from_chars 都不自动 trim。必须先清理或手动跳过。
立即学习“C++免费学习笔记(深入)”;
- 用
s.find_first_not_of(" \t\n\r\f\v")找起始位置,再用s.find_last_not_of(" \t\n\r\f\v")找结束位置 - 或用
std::stringstream(较重,但自动跳过空白):ss >> value,再检查ss.fail()和是否还有剩余字符 -
std::from_chars若想支持空格,得自己截取子串再调用,别试图传入未 trim 的原始指针
真正难的不是转换本身,而是你是否清楚输入来源的格式边界 —— 比如日志行里提取数字,可能混着括号、逗号、单位符号,这时候光靠 stoi 就不够用了。











