
std::span 是 C++20 引入的一个轻量级、非拥有型的数组视图(array view),它不管理内存,只保存指向连续元素的指针和元素个数,用于安全、高效地传递和操作原始数组、std::array、std::vector 等连续内存块。
为什么需要 std::span?
传统上,C++ 函数若要接受“一段连续数据”,常依赖裸指针 + 长度(如 int* data, size_t n)或迭代器对,但容易出错:指针可能为空、长度可能与实际不匹配、类型信息丢失、无法自动推导大小。std::span 把指针和长度封装成一个类型安全、可拷贝、有边界检查(可选)、支持范围 for 的对象,同时零开销——它本身只有两个成员(指针 + size_t),无动态分配,无虚函数。
基本用法和构造方式
std::span 的模板参数是元素类型和扩展长度(std::dynamic_extent 表示运行时确定,最常用):
-
std::span—— 最常见,长度在运行时确定 -
std::span—— 编译期固定长度,能从std::array隐式构造
它支持多种构造来源:
立即学习“C++免费学习笔记(深入)”;
- 从原生数组:
int a[] = {1,2,3}; std::span s{a};(自动推导长度为 3) - 从 std::array:
std::array arr = {4,5,6}; std::span s{arr}; - 从 std::vector:
std::vector v = {7,8,9}; std::span s{v}; - 从指针+长度:
std::span s{ptr, len}; - 子视图切片:
s.subspan(1, 2)得到中间两个元素
安全性和使用注意
std::span 本身不防止悬空(dangling)——它不延长所指对象的生命周期,传入已销毁的 vector.data() 仍是未定义行为。但它提供了一些安全辅助:
-
s.data()和s.size()明确暴露底层信息 -
s[i]不做越界检查(和原生数组一样快),但调试模式下部分标准库实现(如 MSVC 的 /std:c++20 + _ITERATOR_DEBUG_LEVEL=2)会触发断言 - 启用
std::span::at(i)可手动做带异常的越界检查(抛std::out_of_range) - 避免隐式转换陷阱:默认禁止从
std::vector构造(因它不是真正连续存储),也禁止从 const 容器构造非 const span
典型应用场景
std::span 特别适合函数接口设计:
- 替代 C 风格的
void func(int* p, size_t n),写成void func(std::span,语义清晰、调用安全、支持所有连续容器data) - 作为类成员变量暂存某段数据视图(比如解析二进制协议时持有一段 buffer 的子区间)
- 配合算法:可直接传给
std::sort(s.begin(), s.end())或 range-v3 算法 - 跨模块/ABI 边界传递数据(比模板函数更稳定,比裸指针更自描述)
基本上就这些。它不复杂,但容易忽略——一旦习惯用 span 替代裸指针传数组,代码会立刻变得更健壮、更易读、更泛化。










