为何C++中try-catch无法捕获std::stoull的异常?
解决std::stoull对部分非法输入不抛出异常的问题
问题原因
std::stoull的默认行为是读取到第一个非法字符就停止解析:只要输入开头存在合法的数值字符,它就会返回已解析的部分结果,不会触发异常。比如你的输入6yh45gu94j5vun,它会解析开头的合法16进制字符6,返回数值6,而非因为后续的y抛出异常。
只有两种情况stoull会抛出异常:
- 输入中完全没有合法数值字符(比如全是字母或符号)
- 解析出的数值超出
unsigned long long的范围(溢出)
解决方案
要确保整个字符串都是合法的16进制字符,需要利用stoull的第二个参数(size_t* pos)记录解析停止的位置,再通过这个位置判断是否整个字符串都被合法解析。
修改后的代码示例:
#include <iostream> #include <exception> #include <string> #include <sstream> using namespace std; int main() { stringstream ss("6yh45gu94j5vun:"); string valueStr; if (!getline(ss, valueStr, ':')) { return -1; } unsigned long long value; try { size_t pos; value = stoull(valueStr, &pos, 16); // 检查是否整个字符串都被解析完成 if (pos != valueStr.size()) { throw invalid_argument("存在非法字符"); } } catch (const exception& e) { cout << -1; return -1; } cout << value; return 0; }
关键修改说明
- 新增
size_t pos变量,传给stoull的第二个参数,它会存储解析停止的索引位置。 - 解析完成后判断
pos是否等于valueStr.size():相等则说明整个字符串都是合法16进制字符;不等则说明中途遇到非法字符,手动抛出invalid_argument异常触发错误处理逻辑。
内容的提问来源于stack exchange,提问作者mcyrill
相关产品推荐
相关产品推荐

