span — 视图 C++20
std::span是 C++20 引入的非拥有连续序列视图,类似string_view但适用于任意类型的连续数据,是传递数组的现代方式。
基本用法
cpp
#include <span>
#include <vector>
#include <array>
// span 只是 {指针, 长度} 对,不拥有数据,零拷贝
void process(std::span<int> data) {
for (int& x : data) x *= 2;
std::cout << "大小: " << data.size() << "\n";
}
// 可以接受各种连续容器
std::vector<int> v = {1, 2, 3, 4, 5};
process(v); // vector
std::array<int, 5> arr = {1, 2, 3, 4, 5};
process(arr); // array
int c_arr[] = {1, 2, 3, 4, 5};
process(c_arr); // C 数组
process({v.data(), 3}); // 前 3 个元素
// 静态大小 span(编译期已知大小)
std::span<int, 5> fixed_span = arr; // 大小是类型的一部分子视图
cpp
std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::span<int> s = v;
// 子视图(零拷贝)
auto first3 = s.first(3); // {0, 1, 2}
auto last3 = s.last(3); // {7, 8, 9}
auto mid = s.subspan(2, 5); // {2, 3, 4, 5, 6}
// 访问
s[0]; // 0,不检查边界
s.front(); // 0
s.back(); // 9
s.data(); // 底层指针
// 字节视图
auto bytes = std::as_bytes(s); // span<const std::byte>
auto writable = std::as_writable_bytes(s); // span<std::byte>替代 C 风格数组参数
cpp
// 旧写法(不安全,不知道大小)
void old_process(int* arr, size_t n) { /* ... */ }
// 新写法(安全,携带大小信息)
void new_process(std::span<int> arr) {
for (int& x : arr) { /* ... */ }
}
// 只读视图
void read_only(std::span<const int> arr) {
// arr[0] = 1; // 编译错误!
std::cout << arr[0] << "\n";
}
// 2D 数据(行视图)
void process_row(std::span<const float> row) { /* ... */ }
std::vector<float> matrix(rows * cols);
for (int i = 0; i < rows; ++i) {
process_row({matrix.data() + i * cols, (size_t)cols});
}关键认知
std::span 是传递连续数据的现代方式,替代 (T*, size_t) 参数对。它不拥有数据,注意生命周期。std::span<const T> 表示只读视图。静态大小 span<T, N> 在编译期检查大小,更安全。