解决什么问题?
// ❌ 问题:把字符串切一段出来,就要分配内存
std::string full = "user:warren:logged_in";
std::string name = full.substr(5, 6); // "warren" → 分配堆内存!
// ✅ string_view:只记录指针和长度,不拷贝
std::string_view full_sv = full;
std::string_view name_sv = full_sv.substr(5, 6); // "warren" → 不分配!
// name_sv.ptr 指向 full 内部第 6 个字符的位置
什么时候用?
| 场景 | 用 string_view |
|---|---|
| 函数参数,只读字符串 | void parse(std::string_view input)——接受 string、char*、string_view 而不拷贝 |
| 子串提取,不需要修改 | sv.substr(pos, len) 不分配内存 |
| 快速比较前缀/后缀 | sv.starts_with("http") sv.ends_with(".png") |
| 日志/消息解析 | 从大字符串中切出各字段而不拷贝 |
致命陷阱:生命周期
std::string_view get_name() {
std::string temp = "temporary";
return temp; // ✅ 赋值时 temp 还活着
} // ❌ temp 析构,sv 悬垂!
auto sv = get_name();
std::cout << sv; // 💥 Use-After-Free!可能打印出乱码或 crash
规则:string_view 不拥有数据。你必须保证原始字符串活到 string_view 用完。
函数参数的最佳实践
// ❌ 不好:只接受 string,传 char* 会隐式构造 string(分配内存)
void parse(const std::string& s);
// ✅ 好:接受 string_view,字符串字面量/char*/string 都行,不拷贝
void parse(std::string_view sv);
parse("hello"); // char* → 不拷贝
parse(std::string("x")); // string → .data()+size 被 view 借用
parse(some_view); // view → 直接复制指针+长度