substr越界会抛出std::out_of_range异常,因标准要求pos>str.length()或pos+count>str.length()时必须报错;常见原因是直接用find返回的npos(极大值)作pos参数而未校验。
substr 为什么一越界就崩溃?
不做运行时边界检查,越界直接触发
异常(debug 模式下可能直接 abort)。这不是“崩溃得不合理”,而是标准明确要求:当
或
且
非空时,抛异常。
常见诱因:
用
返回的
直接传给
——
是极大值(如
),必然越界
计算起始位置时没校验是否
是无符号,但
隐式转换
后负数会绕成极大值)
传入的
过大,比如想取“剩余全部”却硬写
安全截取字符串的惯用写法
别依赖 try/catch 捕获
——性能差、掩盖逻辑缺陷。应该在调用前主动裁剪参数:
起始位置
:用
保证不超长
截取长度
:用
,注意先确保
更简洁的写法:
,前提是
已合法
示例:
立即学习
“
C++免费学习笔记(深入)
”;
npos 传给 substr 的典型错误现场
这是最常被忽略的坑:
是
类型的极限值,不是 -1。一旦你把它当整数用,比如
,
仍是极大值,
必抛异常。
C函数速查手册(CHM版)
C函数速查手册(CHM版)
下载
正确做法只有两个:
显式判断
后再计算偏移
用
替代(C++17 起),它支持
的宽松语义:越界时自动截断到末尾,不抛异常
例如用
:
substr 性能和内存注意点
返回新字符串,意味着堆分配和字符拷贝。如果只是临时读取、不修改,优先用
(C++17)或
+ 长度;若必须用
,注意:
不要在循环里反复
大字符串的开头(如逐词解析),改用
+ 偏移推进
移动语义对
返回值无效——它本来就是新建对象,不存在“移动旧字符串”的优化空间
Release 模式下异常开销小,但避免异常仍是更可控的做法
真正难处理的不是“怎么截”,而是“怎么确定该截哪儿”——
/
的返回值是否为
,这个判断漏掉一次,后面所有
都是定时炸弹。
substrstd::out_of_rangepos > str.length()pos + count > str.length()strfindstd::string::npossubstrnpos18446744073709551615(虽然 size_tcount1000out_of_rangeposstd::min(pos, str.length())lenstd::min(len, str.length() - pos)pos str.substr(pos, std::min(len, str.size() - pos))posstd::string s = "hello";
size_t pos = s.find("xyz"); // 返回 npos
if (pos != std::string::npos) {
auto sub = s.substr(pos, 2); // 安全
} else {
auto sub = ""; // 或 fallback 值
}std::string::npossize_ts.substr(s.find("x") + 1)npos + 1substr!= nposstd::string_viewsubstrstring_viewstd::string_view sv = s;
auto safe_sub = sv.substr(100, 10); // 返回空 view,不崩溃substrstd::string_viewconst char*substrsubstrfindsubstrfindrfindnpossubstr