[C++面试] span<char>和string_view的差别

1、概念

  • std::string_view是领域特定设计(字符串)。C++17引入,仅用于处理以空字符(\0)结尾的字符序列;仅支持字符类型(如 charwchar_t、std::string),用于高效访问字符串数据,不复制数据、只读。
  • std::span<char>通用抽象(连续内存),强调类型安全和泛用性。C++20引入,是通用连续内存序列的视图。span支持任意类型(如 int、自定义类型),可引用数组、容器或原始内存块,支持读写操作(若模板参数非 const
// string_view示例:只读访问字符串
std::string s = "hello";
std::string_view sv(s);  // 直接引用,无需复制

// span示例:读写访问字符数组
char buffer[10];
std::span<char> sp(buffer);
sp[0] = 'A';  // 可修改数据

​2、string_view

  • string_view 仅限字符类型,隐式假设数据为字符串(如自动处理空终止符)
  • string_view 提供字符串专用方法,如 substr(截取子串)、find(查找字符 / 子串)、starts_with(判断是否以某子串开头)等,完全围绕字符串语义设计,适合字符串处理
  • string_view 存储指针和字符数,可能包含空终止符标记
  • string_view 可能因隐式空终止符导致边界检查开销
  • string_view 因隐式绑定字符类型,可能因误用非字符串数据(如二进制数据)导致未定义行为
// string_view的字符串操作
std::string_view sv = "hello world";
auto pos = sv.find("world");  // 字符串查找

// span的泛型操作
std::vector<int> vec = {1, 2, 3};
std::span<int> sp(vec);
std::sort(sp.begin(), sp.end());  // 支持泛型算法

​3、span

  • span 无类型限制,需显式指定数据类型,支持泛型编程(如处理二进制缓冲区)
  • span 提供通用序列操作(随机访问、迭代器遍历),还有 size()(获取元素个数)、data()(获取数据指针)、first(n)/last(n)(取前 / 后 n 个元素),无字符串语义
  • span 存储指针和元素数量(如 char 数组的元素数等于字节数),类型系统保证安全
  • span 完全依赖显式长度,无额外检查,适合高性能场景(如二进制流处理)
  • span 强制显式类型声明,避免隐式转换错误(如误将 int 数组视为 char 数组)
int numbers[] = {1, 2, 3};
std::span<char> sp(numbers);  // 编译错误!类型不匹配
std::span<int> sp(numbers);    // 正确
  • span 支持动态长度(span<T>)和静态长度(span<T, N>),静态长度在编译时可优化边界检查
int arr[5] = {1, 2, 3, 4, 5};
std::span<int, 5> fixedSpan(arr);  // 编译时已知长度

 span 提供 subspan()first()last() 等方法,支持灵活截取子视图

int arr[] = {1, 2, 3, 4, 5};
std::span<int> sp(arr);
auto sub = sp.subspan(1, 3);  // 截取第1到第3个元素
// string_view潜在风险:未正确处理非空终止数据
char data[] = {'a', 'b', 'c'};  // 无空终止符
std::string_view sv(data, 3);    // 需显式指定长度

// span的类型安全:避免隐式转换
int numbers[] = {1, 2, 3};
std::span<int> sp(numbers);  // 明确类型,无歧义

4、string_view的生命周期风险

4.1  string_view的生命周期风险

string_view 不管理底层数据的生命周期,若原始字符串被释放,string_view 会成为悬空引用,导致未定义行为

std::string_view createView() {
    std::string tmp = "only_in_this_func";
    return tmp;  // tmp 被销毁后,返回的 string_view 无效!
}

4.2  string_view 对非空终止符的隐式处理

string_view 从 const char* 构造时,默认假设字符串以 \0 结尾,但若数据未包含 \0,可能导致越界访问

char data[] = {'a', 'b', 'c'};  // 无空终止符
std::string_view sv(data);       // 错误!隐式假设以 \0 结尾

// 需显式指定长度(如std::string_view(data, size)),否则易因空终止符误判边界。

5、补充

在C++核心指南(C++ Core Guidelines)中,为何推荐优先使用string_viewspan而非原始指针? 

  • 安全性:两者封装了指针和长度,避免越界访问(如 span 的 size() 检查)
  • 语义明确string_view 表示字符串只读视图,span 表示连续内存,代码意图更清晰
  • 兼容性:支持多种数据源(如数组、容器、内存池),减少代码重复
// 推荐用法:使用string_view替代const char*
void read_data(std::string_view data);  

// 推荐用法:使用span替代指针+长度
void process_buffer(std::span<char> buffer);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值