std::string_view 是 C++17 引入的一个非常实用的轻量级字符串工具。简单来说,它就像是给一段现有的字符串拍了一张“快照”或提供了一个“观察窗口”。

它本身不拥有字符串的数据,也不负责管理内存,只是简单地记录了一个指针(指向字符串的开头)和一个长度

在 C++17 之前,我们写函数接收字符串参数时,通常有两种选择,但它们都有各自的痛点:

  • const std::string&:看似高效,但如果你传入一个字符串字面量(比如 "hello"),编译器会偷偷在后台创建一个临时的 std::string 对象,这会产生不必要的内存分配和拷贝开销。
  • const char*:虽然轻量,但它不知道字符串有多长(需要遍历找 \0),而且不安全,接口也不够现代。

std::string_view 完美解决了这些问题,它的核心优势在于:

  1. 零拷贝(Zero-copy):无论是传入 std::string、字符串字面量("hello")还是字符数组,它都不会拷贝数据,只是记录一下指针和长度,构造成本极低。
  2. 接口统一:一个 std::string_view 参数就能通吃各种类型的字符串来源,不再需要写多个函数重载。
  3. 高效的切片操作:当你需要截取子串时,std::string 的 substr() 会分配新内存并拷贝数据;而 std::string_view 的 substr() 仅仅是移动了一下指针、改了一下长度,时间复杂度是 O(1),完全不消耗额外内存
#include <iostream>
#include <string>
#include <string_view>

// 最佳实践:只读字符串参数,优先使用 string_view
void print_info(std::string_view sv) {
    std::cout << "内容: " << sv << ", 长度: " << sv.length() << std::endl;
}

int main() {
    std::string str = "Hello C++";
    const char* c_str = "Hello C";
    
    // 无论是 std::string 还是 const char*,都能完美接收,且无额外拷贝
    print_info(str);      
    print_info(c_str);    
    print_info("字面量"); 

    // 高效的切片(截取子串),不产生新内存分配
    std::string_view sv = str;
    std::string_view sub = sv.substr(0, 5); // 只指向 "Hello",不拷贝
    std::cout << "子串: " << sub << std::endl; 
    
    return 0;
}

 

std::string_view 虽然快,但它把内存管理的责任完全交给了你。因为它不拥有数据,所以使用时必须严格遵守以下规则:

严防“悬空视图”(Dangling View)
这是最大的陷阱!你必须保证原始字符串的生命周期长于 string_view。绝对不能返回指向局部变量的 string_view

// ❌ 错误示范:极其危险!
std::string_view get_bad_view() {
    std::string local_str = "临时数据";
    return local_str; // 函数结束 local_str 被销毁,返回的视图指向了已释放的内存!
}

不保证以 \0 结尾
C 语言风格的函数(如 printf("%s")fopen 等)依赖字符串末尾的 \0 来判断结束。std::string_view 可能会指向字符串中间的一段,末尾没有 \0。因此,不能直接把 sv.data() 传给老旧的 C 语言 API

只读不可修改
它只是一个“视图”,你不能通过它来修改字符串的内容,也不能用它来拼接、插入或删除字符。

用 std::string:当你需要拥有这段字符串、需要修改它、需要长期保存(比如存入类成员变量或容器中),或者不想操心原始数据什么时候被释放时。

用 std::string_view:当你的函数只是“看一眼”字符串(只读参数),或者在做高频的字符串解析、切片、分词,且能保证原始数据一直有效时。

标签: std::string, std::string_view, 字符串, 零开销

上一篇: c++之ranges(一)
下一篇: 没有了

添加新评论