substr用于提取子字符串,有两个重载:substr()取全部,substr(pos,len)从pos起取len个字符;pos越界抛异常,len超长自动截断。

substr 的基本调用方式和参数含义
substr 是 std::string 的成员函数,用来提取子字符串。它有两个重载版本:substr()(无参,默认取从 0 到末尾)和 substr(size_t pos) 或 substr(size_t pos, size_t len)。关键点在于:第一个参数 pos 是起始下标(从 0 开始),第二个参数 len 是要取的字符个数,不是结束下标。
常见错误是把 len 当成“结束位置”,比如想取索引 2 到 5 的字符就传 substr(2, 5)——这实际会取 5 个字符(即索引 2~6),很可能越界或结果不对。
- 如果
pos == string.size(),返回空字符串"",不会报错 - 如果
pos > string.size(),抛出std::out_of_range - 如果
len超出剩余长度,substr自动截断到末尾,不报错
安全获取子串:避免 out_of_range 异常
直接调用 substr(pos, len) 前,必须检查 pos 是否合法。C++ 标准库不帮你做边界校验(除了 pos > size() 这一条件),所以容易在运行时崩溃。
推荐做法是先用 size() 做前置判断,或用 min 控制长度:
立即学习“C++免费学习笔记(深入)”;
std::string s = "hello";
size_t pos = 10;
size_t len = 3;
if (pos <= s.size()) {
std::string sub = s.substr(pos, std::min(len, s.size() - pos));
}注意:不能写 pos 来判断,因为 <code>pos == s.size() 是合法的(返回空串);但 pos > s.size() 才真正越界。
和 C 风格字符串、find 配合使用的典型场景
实际中,substr 很少单独用,常配合 find、rfind 或 find_first_of 提取分隔符之间的内容。比如解析路径中的文件名:
std::string path = "/home/user/file.txt";
size_t last_slash = path.rfind('/');
if (last_slash != std::string::npos) {
std::string filename = path.substr(last_slash + 1); // "file.txt"
}-
rfind返回std::string::npos(即size_t最大值)表示未找到,必须判空再调substr -
substr(pos + 1)这种写法隐含假设pos + 1 ,若 <code>pos是最后一个字符下标,pos + 1 == size()仍合法;但若pos == npos,加 1 后变成 0,会导致取整个字符串——这是典型逻辑漏洞
性能与拷贝:substr 返回的是新对象,不是视图
substr 总是分配新内存并拷贝字符,返回一个独立的 std::string。它不是类似 std::string_view 的只读视图,因此频繁调用可能引发不必要的内存分配和复制开销。
如果你只是临时读取、不修改、且确定源字符串生命周期足够长,优先考虑 std::string_view:
std::string s = "abcde"; std::string_view sv = std::string_view(s).substr(1, 3); // 不拷贝,O(1)
但要注意:string_view 不拥有数据,源 string 被销毁后,sv 变成悬垂指针——这点比 substr 更容易被忽略。


















