std::string::substr 不会越界崩溃但行为未定义:pos > size() 且 pos ≠ size() 时抛 std::out_of_range,count 超长则静默截断;调试时异常可能被吞或使用了 noexcept 版本;安全做法是先检查 pos。

substr 会越界崩溃吗?
不会自动崩溃,但行为未定义——std::string::substr 在 pos 超出字符串长度时,若 pos != size() 就抛 std::out_of_range;而 count 超长会被静默截断。
常见错误现象:调试时程序突然终止,堆栈指向 substr 调用处,但没打印异常——可能因为异常被吞了,或你用了 noexcept 版本(C++20 起部分实现支持)。
- 安全写法:先检查
pos ,再调用 - 典型误用:
s.substr(s.size() + 1)直接抛异常;s.substr(s.size())合法,返回空串 - C++20 前不支持
substr(pos, n)中n == std::string::npos的“从 pos 到末尾”语义——其实它本来就支持,npos是默认值,但很多人不敢写,硬写成s.substr(pos)
中文字符截取为什么乱码?
substr 是字节操作,不是字符操作。UTF-8 下一个中文占 3 字节,直接按索引切会把某个汉字的中间字节截断,导致后续解析出错或显示为 。
使用场景:日志提取、路径处理、协议字段分割——只要原始数据是纯 ASCII(如数字、字母、下划线),substr 安全;一旦含中文、emoji 或其他多字节字符,就得换方案。
立即学习“C++免费学习笔记(深入)”;
- 别用
s.substr(5, 2)截“第 5 个汉字起两个汉字”,它切的是字节 - 真要按字符切,得先用
std::codecvt_utf8(已弃用)或第三方库(如 ICU、utf8cpp),或手写 UTF-8 解码跳过字节 - 简单绕过:改用
std::string_view配合std::find找分隔符,避免索引计算
substr 返回的是新字符串还是引用?
返回的是新 std::string 对象,深拷贝内容。不是视图,也不是引用,更不是 string_view(C++17 才有)。
性能影响明显:大字符串反复 substr 会频繁分配内存、拷贝字节,尤其在循环里。
- 如果只是临时查看、不修改、不存储,优先用
std::string_view(s.data() + pos, len)替代 - 注意
string_view生命周期依赖原字符串,不能返回局部string的substr再转成string_view - 编译器一般不做 RVO 优化
substr返回值,别指望它“零成本”
和 C 风格 strncpy 有什么区别?
根本不是一类东西:substr 是 C++ string 成员函数,输入是逻辑位置;strncpy 是 C 库函数,操作裸指针,还要手动确保目标缓冲区够大、结尾补 \0,极易溢出或漏终结符。
错误常发生在混用:比如把 c_str() 结果传给 strncpy,再拿回来构造 string,结果忘了 strncpy 不保证写 \0,导致后续 string 构造读到垃圾内存。
- 现代 C++ 中,几乎不该出现
strncpy;替代方案是std::string+substr+ 移动语义 - 如果必须对接 C API,用
s.copy(buf, n, pos)(不补\0)或snprintf更安全 -
substr不接受缓冲区指针,也不修改原串——这点比 C 函数干净得多
最易被忽略的点:substr 的 pos 是 size_t,负数会回绕成极大正数,直接触发异常。别用 int 变量存位置再传进去。










