std::stoi 直接调用易因非法输入抛异常导致崩溃,空串、纯空白、非数字前缀触发 std::invalid_argument,超范围触发出 std::out_of_range;std::from_chars 更安全高效但需手动检查完整转换。

std::stoi 用法与常见崩溃原因
直接调用 std::stoi 是最常用的方式,但它在输入非法时会抛出 std::invalid_argument 或 std::out_of_range 异常,不加捕获会导致程序终止。
- 空字符串、纯空白(如
" ")、非数字前缀(如"abc123")都会触发std::invalid_argument - 超出
int表示范围(如"2147483648")会触发std::out_of_range - 它会自动跳过开头空白,但只转换到第一个非法字符为止——
std::stoi("123abc")返回123,不报错 - 若需严格匹配整个字符串,得手动检查是否所有字符都被消费:
size_t pos; int val = std::stoi(s, &pos); if (pos != s.length()) { /* 转换未覆盖全串 */ }
安全替代:std::from_chars(C++17 起)
std::from_chars 是无异常、零分配、高性能的底层方案,适合对稳定性或性能敏感的场景(如高频解析、嵌入式、游戏逻辑)。
- 不跳过空白,不处理前导
+/-以外的符号,也不支持进制自动推断(必须显式传10) - 返回
std::from_chars_result,其中ec成员为std::errc::invalid_argument或std::errc::result_out_of_range,可直接判断 - 它只读取连续数字部分,不会自动截断;
std::from_chars("123abc", ...)的ptr指向'a',需自行比对终点 - 示例:
int val; auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), val, 10); if (ec == std::errc{} && ptr == s.data() + s.size()) { /* 全串合法且完全转换 */ }
从 int 转 string:to_string vs stringstream vs fmt
std::to_string 简单直接,但不支持格式控制(如补零、进制、科学计数);std::stringstream 灵活但有构造/析构开销;fmt::format(第三方)兼顾性能与表达力。
-
std::to_string(42)→"42",但std::to_string(0)就是"0",无法输出"0042" -
std::stringstream可用std::setfill和std::setw补零:std::stringstream ss; ss << std::setfill('0') << std::setw(4) << 42; // "0042" - C++20 的
std::format尚未被所有编译器默认启用;若可用,std::format("{:04}", 42)更简洁 - 注意:
std::to_string对负数也正常工作,但结果含负号,长度不可控
跨平台兼容性与宽字符陷阱
Windows 上常见 std::wstring(UTF-16),而 std::stoi 等只接受 std::string(窄字符)。别直接强转指针,会乱码或崩溃。
立即学习“C++免费学习笔记(深入)”;
- 不要写
std::stoi((char*)wstr.c_str())—— 宽字符指针当窄字符用是未定义行为 - 需要转换宽字符串时,先用
std::wstring_convert<:codecvt_utf8>>(已弃用)或更现代的std::from_chars配合std::wstringtostd::string编码转换(如 UTF-8) - Linux/macOS 默认多为 UTF-8
std::string,但若涉及文件名或系统 API 返回宽字符串,仍需小心 - 若项目已用
QString或CFString,优先用其原生方法(如QString::toInt()),避免中间编码转换损耗
实际转换逻辑里,最易被忽略的是“是否要求整串匹配”和“是否接受前导空白”——这两个语义差异直接决定该选 std::stoi 还是 std::from_chars,而不是看哪个函数名更短。











