用 substr 最直接:s.substr(n) 返回从第 n 字节起的子串,安全且不修改原串;erase(0,n) 会原地修改但可能重分配;string_view::remove_prefix(n) 更轻量但需确保 n 合法。

字符串开头截取固定字节(非字符)用 substr 最直接
C++ 的 std::string 是字节序列,不是 Unicode 字符串。所谓“从开头减去固定字节”,本质就是丢弃前 N 个字节,保留剩余部分——这等价于从索引 N 开始取子串。substr 正是为此设计的:s.substr(n) 返回从第 n 个字节起的全部内容。
常见错误是误用 erase(0, n):它确实能修改原字符串,但会触发内存重分配(尤其对大字符串),且不可逆;而 substr 更轻量、语义清晰、不破坏原串。
- 若需新字符串:直接写
s.substr(n),当n >= s.size()时返回空串,安全 - 若必须原地修改且确认
n合法:可用s.erase(0, n),但要确保n ,否则抛 <code>std::out_of_range - 不要用
std::string::data() + n构造新串——data()不保证结尾有\0,且构造时需显式指定长度,易出错
处理 UTF-8 字符串时不能直接按字节截断
如果字符串含中文、emoji 等 UTF-8 编码内容,按字节截取可能切在某个字符中间,导致后续解析失败(如显示 或 std::runtime_error 报“invalid UTF-8”)。这时“减去固定字节”本身就有风险,应优先考虑按 Unicode 码点或 UTF-8 字符个数操作。
标准库不提供 UTF-8 拆分,需借助第三方(如 utf8cpp)或手动验证字节模式:
- UTF-8 单字符占 1–4 字节,首字节决定长度:
0xxxxxxx(1字节)、110xxxxx(2字节)、1110xxxx(3字节)、11110xxx(4字节) - 若已知要跳过前
k个 UTF-8 字符,得遍历计数合法字符,再得到对应字节偏移,而非直接用k - 若只是协议层要求“头部剥离 N 字节”(如 HTTP header 去掉
"HTTP/1.1 "这 11 字节),且明确该部分为 ASCII,则无需 UTF-8 检查
substr 和 erase 的性能与所有权差异
substr 在 C++11 及以后通常为 O(1) 复制(small string optimization 下可能无分配),但返回的是新对象;erase 是 O(N) 移动后续字节,且修改原对象。
- 频繁截取且不保留原串?用
s = s.substr(n)—— 现代编译器常优化为移动赋值 - 只读场景或需保留原串?必须用
substr,别改原串 - 使用
std::string_view(C++17)更优:std::string_view{s}.remove_prefix(n)零拷贝、无内存分配,但要求原字符串生命周期长于 view - 注意:
string_view::remove_prefix(n)不检查边界,n > size()导致未定义行为
容易被忽略的边界情况
所有操作都依赖 n 是否越界,但不同函数行为不一致,容易踩坑:
-
s.substr(n):当n == s.size()返回空串;n > s.size()抛std::out_of_range -
s.erase(0, n):当n >= s.size()清空字符串,不会抛异常 -
string_view sv{s}; sv.remove_prefix(n):仅当n 安全,否则 UB —— 必须手动判断 - 空字符串
""对所有操作都合法,但n=0时结果恒为原串,别误以为“没生效”
实际写代码时,先想清楚:是要新串还是改原串?是否涉及 UTF-8?生命周期能否保证?这几个问题定了,选哪个 API 就很自然了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











