std::span是C++20提供的零拷贝切片方案,通过指针+长度实现近似Python切片语义,不复制数据但需确保原始容器生命周期长于span;越界访问导致未定义行为,而C++11/17需用vector迭代器构造实现显式拷贝切片。

std::vector 用 std::span 做零拷贝切片(C++20)
原生 C++ 数组不支持切片,但 std::span 是最接近 Python 切片语义的现代方案:它不复制数据,只持有一个指针 + 长度,开销几乎为零。
- 必须确保原始容器生命周期长于
std::span,否则悬空指针 →std::span不管理内存 -
std::span构造时可传入指针和长度,或容器的data()和size() - 切片范围需手动检查:越界不会抛异常,行为未定义 —— 例如
span.subspan(10, 5)在长度不足时直接 UB
std::vector<int> v = {1, 2, 3, 4, 5};
std::span<int> s{v.data() + 1, 3}; // [2,3,4],等价于 v[1..4]
兼容 C++11/17 的手动切片:用 std::vector 构造函数
如果不能用 C++20,最稳妥的方式是构造新 std::vector,明确表达“复制切片”的意图,避免误用裸指针。
- 用迭代器区间构造:
std::vector<T>(begin_it, end_it),注意end_it是开区间终点 - 下标计算易错:取索引
[start, start + len)要写成v.begin() + start和v.begin() + start + len - 性能代价明确:O(n) 拷贝,不适合大数组高频切片
std::vector<int> v = {1,2,3,4,5};
auto slice = std::vector<int>(v.begin() + 1, v.begin() + 4); // [2,3,4]
裸数组(T[N])切片必须自己算地址,且无法自动知道长度
C 风格数组没有元信息,sizeof(arr)/sizeof(arr[0]) 只在作用域内有效;传参后退化为指针,长度丢失 —— 这是切片出错的高发场景。
- 函数参数中裸数组必须显式传长度:
void f(int* arr, size_t len),不能只写void f(int arr[]) - 切片本质就是偏移指针:
int* slice = arr + offset,但调用者必须保证offset + length - 没有边界检查,
slice[i]越界访问不会报错,可能静默崩溃或数据污染
别用 std::string_view 类比数组切片
std::string_view 看似是字符串的 std::span,但它专为 char 设计,有额外语义(如 find、substr),不能泛化到任意类型。对 int 或自定义结构体数组,强行套用会编译失败。
立即学习“C++免费学习笔记(深入)”;
-
std::string_view的substr()返回仍是string_view,但它是特化实现,不是通用切片接口 - 试图用
std::string_view包装int[]:编译错误 —— 构造函数只接受const char*或std::string - 真正需要泛型切片,请坚持用
std::span(C++20)或封装自己的ArrayView<T>
C++ 没有内置切片语法,所有方案都依赖你主动管理生命周期和边界 —— 最容易被忽略的是:哪怕用了 std::span,只要原容器提前析构,切片立刻失效,而且编译器不会提醒。


















