std::span不提供运行时越界检查,仅构造时验证指针有效性(debug模式或调用at()时才有检查),operator[]和data()无边界检查,at()是唯一带检查的访问方式,安全使用需确保内存生命周期长于span且长度准确。
std::span 本身不提供运行时越界检查,直接访问 operator[] 和 data() 都可能越界——它只在构造时验证指针+长度是否合法(且仅当启用了调试模式或手动调用 at())。
构造 std::span 不等于“安全”,而是把责任交还给调用者。标准要求:若传入空指针且长度非零,行为未定义;若指针有效但长度超出实际可用内存,span 仍会构造成功(除非编译器/STL 在 debug 模式下拦截)。
int arr[5] = {1,2,3,4,5};
std::span s{arr}; // 自动推导 size() == 5 int* p = nullptr; std::spans{p, 10}; // UB!即使没访问元素,构造即崩溃(debug 下常触发 assert)
std::vectorv = {1,2,3}; std::span s{v.data(), 10}; // 构造成功,但 s.size() == 10 → 后续访问越界
at() 替代 operator[] 获取运行时边界检查operator[] 和 data() 都不检查索引——它们和裸指针一样快,也一样危险。at() 是唯一标准提供的带检查的随机访问方式,越界时抛出 std::out_of_range。
s[i]:无检查,等价于 *(s.data() + i)
s.at(i):有检查,debug 和 release 下都生效(C++20 要求)s.front()/s.back():不检查空 span,调用前需确认 !s.empty()
std::spans{arr, 3}; // s[5]; // UB —— 不报错,但踩内存 // s.at(5); // 抛 std::out_of_range
std::array 或容器 .data() 使用最稳妥真正安全的前提是:源内存生命周期长于 span,且长度信息准确。std::array、std::vector::data()、栈数组名转指针是最可靠来源。
std::arraya = {1,2,3,4}; std::span s = a; // 类型自动推导,size 编 译期确定,完全安全
std::vectorv = {1,2,3}; std::span s{v.data(), v.size()}; // ✅ 正确;{v.data(), 10} ❌ 错误
std::spanf() { int local[3] = {1,2,3}; return std::span{local}; // 返回悬垂 span!local 栈内存已销毁
span 本身std::span 的设计哲学是“零开销抽象”,不是“安全抽象”。真正的越界防护要依赖:
-fsanitize=address,能捕获绝大多数 span 越界读写/RTCc(运行时检查)或 STL 的 _ITERATOR_DEBUG_LEVEL=2
cppcoreguidelines-pro-bounds-array-to-pointer-decay)别指望 span 自己拦住所有错误——它只是帮你把“裸指针+长度”这个易错模式封装得更清晰,越界检查这件事,终究得靠人写对、工具兜底。