std::span 是c++20引入的轻量级内存视图,不分配也不管理内存,仅持有一对指针(data + size),用于安全引用已存在连续内存;其生命周期不得超过所指内存,否则导致悬空访问。

std::span 是什么,它不帮你分配内存
std::span 不是容器,也不管理内存生命周期。它只是轻量级的“视图”——一对指针(data() + size()),用来安全地引用已存在的连续内存块,比如数组、std::vector 的底层数据或栈上 C 风格数组。
你传给它的内存必须比 std::span 活得久;否则就是悬空视图,访问即未定义行为。
- 常见错误现象:
std::span<int> s = get_local_array();</int>中get_local_array()返回栈数组,函数返回后s指向垃圾内存 - 正确用法:绑定到
std::vector的data()、全局/静态数组、或明确生命周期更长的栈数组(如函数参数传入的数组) - 性能影响:零开销抽象,
sizeof(std::span<t>)</t>通常就是两个指针大小(16 字节)
怎么构造 std::span 才不会越界
构造时不做边界检查,越界全靠你负责。但你可以利用模板推导和编译期长度来堵住一部分漏洞。
- 推荐写法:
std::span s{arr};(C++20 起支持 CTAD)——若arr是固定大小数组(如int arr[5];),s.size()就是5,编译期确定 - 危险写法:
std::span{ptr, len}或std::span{ptr, ptr + len}——len错了就直接越界,运行时无提示 - 使用场景:函数参数接收任意连续内存时,优先用
std::span<const t></const>替代T*+size_t,调用方更清晰,你也少传错一个参数
operator[] 和 at() 的区别很关键
operator[] 不检查索引,行为和原生指针一致;at() 做范围检查,越界抛 std::out_of_range。但注意:这不是“安全默认”,而是明确分工。
立即学习“C++免费学习笔记(深入)”;
- 常见错误现象:以为
span[i]会像vector::at()一样检查——实际完全不会,i 超出span.size()就是未定义行为 - 性能差异:
operator[]是纯指针偏移,at()多一次比较 + 异常路径开销,调试时可用,热路径慎用 - 建议:内部逻辑信任输入范围时用
[];对外部不可信输入(如用户传来的索引)必须用at()或手动if (i
为什么不能把 std::span 当成智能指针用
std::span 没有所有权语义,不参与 RAII,不重载 = 为深拷贝,也不阻止你把它绑定到即将销毁的对象上。
- 容易踩的坑:
auto s = std::span{v.data(), v.size()}; v.clear();——v.clear()可能释放内存,s立刻失效 - 兼容性注意:C++20 引入,老项目需确认标准版本;MSVC/GCC/Clang 主流版本都支持,但 Clang 10 以前对 CTAD 支持不完整
- 替代方案对比:比起裸指针+长度,
std::span提供first()/last()/subspan()等安全切片接口,但这些操作仍不检查源视图是否有效
最常被忽略的一点:没人替你跟踪底层内存的生命周期。哪怕所有语法都对,只要原始数据提前结束生命,std::span 就是纸老虎。










