应优先用 std::string_view 切分并存入 std::vector(预 reserve),避免转 std::string 造成堆分配;若需 list,则确保源字符串生命周期覆盖容器,手写切分函数比 regex/boost 更快更轻量。

std::string_view 切分时别直接构造 std::string
用 std::string_view 做切分,目标却是往 std::list<:string></:string> 里塞,这是典型性能浪费——每次调用 std::string{sv} 都触发堆分配和字符拷贝。除非后续逻辑真要修改内容或延长生命周期,否则没必要转成 std::string。
更合理的做法是让容器持有 std::string_view,但注意:std::list<:string_view></:string_view> 只在原始字符串生命周期内有效。常见错误是把临时 std::string 的 substr() 结果转成 string_view 后存进 list,结果原始字符串一析构,所有 view 全变悬垂指针。
- 安全前提:确保源字符串(比如传入的
const std::string& s或全局/静态缓冲区)生命周期 ≥ list 生命周期 - 若必须存
std::string,优先用std::string{sv.begin(), sv.end()}而非std::string(sv)(后者可能多一次长度计算) - 切分函数返回
std::list<:string_view></:string_view>比返回std::list<:string></:string>更轻量,也更利于编译器优化
手写切分函数比 std::regex 或 boost::split 快得多
正则表达式做单字符分隔(如按空格、逗号)是杀鸡用牛刀,std::regex 构造开销大、匹配慢、还依赖 locale;boost::split 默认复制字符串,且返回 std::vector,转 std::list 又多一次遍历。
一个零分配、仅遍历一次的切分函数足够应对大多数场景:
立即学习“C++免费学习笔记(深入)”;
std::list<std::string_view> split_sv(std::string_view s, char delim) {
std::list<std::string_view> res;
size_t start = 0;
while (start < s.size()) {
auto end = s.find(delim, start);
if (end == std::string_view::npos) {
res.emplace_back(s.substr(start));
break;
}
if (end > start) {
res.emplace_back(s.substr(start, end - start));
}
start = end + 1;
}
return res;
}
-
emplace_back避免std::string_view的拷贝构造(虽 cheap,但无必要) - 跳过空字段:只在
end > start时插入,避免连续分隔符产生空 view - 不依赖
<algorithm></algorithm>或额外容器,cache 友好,实测比std::regex_token_iterator快 5–10 倍
std::list 不是默认最优选择:考虑 std::vector<:string_view> + reserve
很多人选 std::list 是觉得“切分数量不确定,链表插入快”。但实际中,切分结果通常用于遍历或传给其他函数,而 std::list 的内存不连续性导致 cache miss 频繁,迭代速度常比 std::vector 慢 2–3 倍。
如果只是切完立刻用(比如循环处理每个字段),std::vector<:string_view></:string_view> + reserve() 是更优解:
- 预估最大切分数(如按逗号切,最多
s.length()个字段),调用v.reserve(estimated_count) - 插入仍用
emplace_back,避免重复 realloc - 若后续需频繁插入/删除中间元素,再考虑
std::list;否则 vector 几乎总是更快 - 注意:
std::vector移动成本低,返回值优化(RVO)后无额外开销
Windows MSVC 下 string_view::find 可能慢于手动循环
MSVC 2019/2022 的 std::string_view::find 在小字符串(
若切分目标是超短字符串(如 HTTP header key/value、CSV 小字段),可改用手动扫描:
for (size_t i = start; i < s.size(); ++i) {
if (s[i] == delim) {
res.emplace_back(s.substr(start, i - start));
start = i + 1;
break;
}
}
- 对长度
- 但代码变长,可读性略降;建议仅在 profiler 确认该路径是热点时才替换
- Linux GCC/Clang 下
find优化较好,通常无需替换
真正影响性能的从来不是容器类型或 view 本身,而是数据生命周期管理是否严谨、切分逻辑是否贴合实际输入特征。盲目套用 “string_view 更快” 或 “list 更灵活”,反而容易踩进悬垂指针或 cache 反模式的坑里。



















