Skip to content

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> 在编译期检查大小,更安全。

系统学习 C++ 生态,深入底层架构