C++20 中的 std::span 与数组视图的使用

在 C++20 之前,处理数组、向量以及其它容器的子序列通常需要自己实现切片逻辑,或者使用标准库提供的 std::arraystd::vector 等,并通过 begin()/end() 等方法手动获取迭代器。
C++20 引入的 std::span(在 <span> 头文件中定义)为这类工作提供了一种轻量级、无所有权的视图(view)。std::span 不是容器,它只保存一个指向元素的指针和一个长度,不能修改其所指向的数据的大小,只能访问。

1. std::span 的基本定义

template<class T, std::size_t Extent = std::dynamic_extent>
class span;
  • T 是元素类型。
  • Extent 是元素数量,若未知可用 std::dynamic_extent

2. 如何构造 std::span

int arr[5] = {1, 2, 3, 4, 5};
std::span <int> sp1(arr);                    // 整个数组
std::span <int> sp2(arr, 3);                 // 前 3 个元素
std::span <int> sp3(arr + 1, 3);             // 从 arr[1] 开始的 3 个元素

`std::vector

vec = {10, 20, 30, 40};` `std::span sp4(vec);` // 直接使用容器,span 会调用 `data()` 与 `size()`。 ### 3. 常用成员函数 | 成员 | 说明 | |——|——| | `size()` | 返回元素数量 | | `data()` | 返回指向首元素的指针 | | `empty()` | 判断是否为空 | | `operator[]` | 访问指定下标 | | `front()`, `back()` | 访问首尾元素 | | `subspan(n)` | 从第 n 个元素开始的子 span | | `last(n)` | 末尾 n 个元素的子 span | | `first(n)` | 开始 n 个元素的子 span | ### 4. 与容器迭代器的兼容 `std::span` 的 `begin()` 与 `end()` 返回原始指针,可直接用于范围-based for 循环。 “`cpp for (int x : sp1) std::cout sp = std::span(new int[10], 10); // 错误:sp 只是一视图,未负责释放内存 “` 建议只在栈上或已有容器的数据上创建 `span`,不用于动态分配。 ### 6. 典型使用场景 * **函数参数**: “`cpp void process(std::span data) { // 对 data 做处理,读写都可以 } “` 这样函数既可以接受数组、向量,也能接受子序列。 * **子序列访问**: “`cpp void print_first_half(std::span arr) { auto half = arr.first(arr.size() / 2); for (int v : half) std::cout ` 将任意对象序列化为字节流。 ### 9. 示例代码:排序子范围 下面演示如何用 `std::span` 对向量的一部分进行排序,而不影响其它部分。 “`cpp #include #include #include #include void sort_subrange(std::vector & v, std::size_t lo, std::size_t hi) { std::span sub(v.data() + lo, hi – lo); // 只看 [lo, hi) std::sort(sub.begin(), sub.end()); } int main() { std::vector numbers = {9, 1, 4, 7, 3, 8, 2, 5, 6}; std::cout

发表评论