std::span是C++20引入的非拥有式连续内存视图,封装指针与长度,零开销、类型安全、支持静态/动态长度;可从vector/array/C数组等连续源构造,不适用于list/deque。

std::span 是 C++20 引入的轻量级、非拥有(non-owning)连续内存视图类型,本质是一个“安全指针 + 长度”的封装。它不管理数据生命周期,只提供对已有数组、std::vector、std::array、C 风格数组等连续内存块的只读或可写访问,兼顾效率与安全性。
核心定位:不接管内存,只观察数据
std::span 不分配、不释放、不复制数据,也不延长所引用对象的生存期。它就像一张“内存快照”,必须确保 span 对象存活期间,其背后的数据依然有效——否则行为未定义。
- 适用于函数参数传递,替代
T*+size_t的易错组合 - 零运行时开销:内部通常仅含一个指针和一个大小(静态 extent 下 size 可能完全编译期折叠)
- 支持 const 和非 const 元素类型,可读可写(取决于所引用原始数据的 cv 限定)
两种长度模式:编译期确定 vs 运行时确定
模板参数 Extent 控制长度是否在编译期已知:
-
std::span:静态 extent,长度 5 在编译期固定,size()是 constexpr,无运行时存储开销 -
std::span(即std::span):动态 extent,长度在构造时传入,内部保存 size 值
静态 span 能触发更多编译器优化,也更利于接口契约表达(例如要求“必须传入恰好 4 个 float 的顶点坐标”)。
立即学习“C++免费学习笔记(深入)”;
怎么创建?兼容多种连续数据源
只要数据连续、有起始地址和明确元素数,就能构造 span:
- 从容器:
std::span{vec}、std::span{arr}、std::span{str} - 从迭代器对:
std::span{v.begin() + 2, v.end()} - 从指针+长度:
std::span{ptr, n} - 子视图切片:
s.subspan(1, 3)返回新 span,不拷贝数据
注意:不能从 std::list 或 std::deque 直接构造——它们内存不连续。
为什么比裸指针更安全、更清晰?
std::span 内置边界感知能力:
-
s[i]行为同原生数组(无检查,但语义明确) -
s.at(i)提供可选的运行时越界检查(调试模式下常启用) -
s.front()/s.back()安全获取首尾,空 span 调用会抛异常 - 所有成员函数(
data()、size()、empty()等)语义统一,避免手写ptr + len逻辑出错
类型系统也更健壮:std::span 和 std::span 是不同类型,不可隐式转换,防止误写。











