substr第一个参数是起始位置(从0开始),第二个参数是截取长度而非结束下标;pos超界抛out_of_range,len超剩余长度则自动截断到末尾。
substr 是 std::string 的成员函数,签名是 string substr(size_t pos = 0, size_t len = npos) const。第一个参数 pos 是起始位置(从 0 开始),第二

len 是要截取的长度,不是结束下标。
常见错误是把 len 当成“到第几个字符为止”,比如想取索引 2~5(共 4 个字符),写成 s.substr(2, 5) —— 这实际会取 5 个字符,可能越界或结果不对。
s.substr(2, 4)
s.substr(3),表示从索引 3 到末尾pos 超出字符串长度(但 ≤ s.length())时抛 std::out_of_range;等于 s.length() 是合法的,返回空串len 超过剩余长度时,自动截断到末尾,不会报错substr 按字节操作,不识别 UTF-8 编码边界。一个中文字符占 3 字节,若 pos 或 len 落在某个汉字中间,截出来就是非法 UTF-8 序列,显示为 或解析失败。
substr
std::wstring + std::mbstowcs,或引入 ICU / utf8cpp 库pos 和每个截断点都在字节边界上(比如只在空格、换行、ASCII 标点后切),但这不通用标准库没有内置的 UTF-aware 子串函数,但 C++17 引入了 std::string_view,它和 substr 行为一致(仍是字节级),只是开销更低——不拷贝数据,只持引用和长度。
string_view:string_view sv = s.substr(5, 3);
string_view 不拥有数据,原 string 生命周期必须长于它的使用期utf8::substr(s, start_char_index, char_count)(来自 utf8cpp)错误信息通常是:basic_string::substr: __pos (which is 12) > this->size() (which is 10)。说明你传的 pos 已经超出字符串当前长度。
.length() 或 .size() 就直接算下标,比如 s[i+5] 前没判断 i+5
at() 替代 [] 可提前暴露越界访问,但它不解决 substr 参数问题assert(pos ,或用三元表达式兜底:s.substr(pos > s.size() ? 0 : pos, len)
pos 和 len 的语义、UTF-8 边界、异常触发条件这三点,任一疏忽都会导致线上静默错误或崩溃。尤其服务端处理用户输入时,别假设输入全是英文。