substr首参数为起始位置,次参数为最多截取字符数;常见误用是混淆为结束下标,且pos越界必抛异常;安全写法需先检查pos>=size()再clamp长度。

substr 的参数含义和常见误用
substr 是 std::string 的成员函数,签名是 string substr(size_t pos = 0, size_t len = npos) const。第一个参数是起始位置(从 0 开始),第二个是**最多截取的字符数**,不是结束位置。很多人误以为第二个参数是“到哪个下标为止”,结果传入 s.substr(0, 5) 却想得到索引 0~4 的子串——这没错;但若传 s.substr(2, 5) 而原字符串只有 4 个字符,就会触发 std::out_of_range 异常(当 pos > size() 时)。
关键点:只要 pos ,即使 <code>len 超出剩余长度,substr 也会自动截断到末尾,不会报错;但若 pos > size(),哪怕 len 是 0,也一定抛异常。
安全截取指定长度的通用写法
要“从某位置开始、最多取 N 个字符”,必须先检查边界。最稳妥的方式是手动 clamp:
std::string safe_substr(const std::string& s, size_t pos, size_t len) {
if (pos >= s.size()) return ""; // 起始位置越界,返回空串
size_t actual_len = std::min(len, s.size() - pos);
return s.substr(pos, actual_len);
}
常见使用场景包括解析固定格式日志、分块读取缓冲区、或实现类似 Python 的切片语义。注意:size_t 是无符号类型,直接做减法可能回绕(比如 pos > s.size() 时 s.size() - pos 会变成极大正数),所以必须先判断 pos >= s.size()。
按字节长度 vs 按 Unicode 字符长度
C++ std::string 是字节容器,substr 操作的是字节索引,不是字符。如果字符串含 UTF-8 编码的中文,s.substr(0, 3) 可能只截出一个汉字的前两个字节,导致乱码。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
此时不能依赖 substr:
- 若需按 Unicode 码点截取,得用 ICU、utf8cpp 或 C++20 的
<charconv></charconv>+ 手动遍历 UTF-8 序列 - 若只是处理 ASCII 或已知单字节编码,
substr安全 - 调试时可用
s.length()(字节数)和s.size()(同义)对比s.substr(0, n).length()验证是否截断在合法 UTF-8 边界上
性能与移动语义注意事项
substr 总是返回新字符串,内部执行堆分配(除非启用了 small string optimization 且长度够小)。频繁调用可能成为瓶颈,尤其在循环中。
优化建议:
- 避免在 hot path 中反复
substr,改用std::string_view(C++17 起):它不拷贝数据,只持引用和长度,sv.substr(pos, len)开销极低 - 若必须返回
std::string,且原字符串后续不再使用,可考虑std::move(s).substr(...)—— 但实际效果有限,因为substr本身不接受右值引用重载,仍会拷贝 - 编译器对短字符串(如
"hello".substr(1,2))可能常量折叠,但别依赖
真正容易被忽略的是:UTF-8 场景下看似正确的 substr 调用,运行时可能产生非法字节序列,而标准库不校验——这问题往往在特定输入下才暴露,且难以复现。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










