std::string_view按值传递更优,因其仅16字节且编译器优化好;但必须确保所引用字符串生命周期覆盖全程,否则引发未定义行为。

直接用 std::string_view 做函数参数,能真正避免拷贝——但前提是调用方传入的是生命周期足够长的字符串源;否则不是性能问题,是未定义行为。
为什么传值比 const std::string_view& 更合适
它本身只有两个成员(指针 + size_t),通常 16 字节,现代编译器对这种小类型按值传递优化极好。用 const std::string_view& 反而可能引入间接访问、阻碍内联,还容易让人误以为“引用更安全”。
- 字面量如
"hello"传入时,std::string_view直接构造,零开销 -
std::string s = "world";传入时,隐式转换不触发拷贝,只读取其data()和size() - C 风格字符串如
cstr传入时,会调用strlen推导长度(要求以\0结尾)
哪些字符串源传给 string_view 是危险的
核心原则:原始内存必须活过 std::string_view 的整个使用期。常见陷阱包括:
-
std::string_view{std::to_string(42)}→std::to_string返回临时对象,表达式结束即析构 -
std::string_view{s.substr(5, 3)}→s.substr()返回新std::string,临时对象立即销毁 -
std::string_view{local_str.c_str()}→ 若local_str是局部变量,函数返回后内存失效 -
std::string().data()→ C++11 起不保证非空,可能为nullptr,不能直接传
什么时候必须退回到 const std::string& 或 std::string
遇到以下任一情况,std::string_view 就不再适用:
- 函数内部要调用 C API(如
fopen、printf),需要稳定\0终止符 ——string_view.data()不保证结尾是\0 - 需要拼接、追加、转小写等修改操作 ——
string_view是只读视图,无append、resize等成员 - 要把字符串存进容器长期持有(如
std::vector<:string_view>),而原始字符串是局部或短生命周期的 - 函数签名需兼容 C++14 或更早标准 ——
std::string_view是 C++17 引入
substr 和 remove_prefix 的真实成本
它们返回新 std::string_view,确实不拷贝字符,但所有派生视图仍共享同一块底层内存。一旦原始字符串被移动、析构或重分配(比如 std::string 被 std::move 或 resize),所有依赖它的 string_view 全部失效。
-
std::string_view sv = s;后调用sv.substr(2, 5)→ 安全,只要s还活着 - 但若之后执行
s.clear()或s = "new",原内存可能被释放或覆盖 - 异步回调中保存
string_view→ 必须确保原始字符串在回调执行时仍有效,不能靠“看起来没动过”来赌
最常被忽略的一点:string_view 的“零拷贝”不是免费的——它把生命周期管理责任完全交给了程序员。没有运行时检查,出错就是未定义行为,调试难度远高于内存拷贝慢一点的问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











