使用 std::span
视图容器
std::span
是 C++20 引入的一个轻量级非拥有(non-owning)视图容器,用于表示连续内存序列的视图。它不管理内存,只是提供对现有连续内存的安全访问接口。
基本用法
1. 包含头文件
#include <span>
2. 创建 span
// 从数组创建
int arr[] = {1, 2, 3, 4, 5};
std::span<int> s1(arr);
// 从 vector 创建
std::vector<int> vec = {1, 2, 3, 4, 5};
std::span<int> s2(vec);
// 从指针和大小创建
int* ptr = vec.data();
std::span<int> s3(ptr, vec.size());
3. 访问元素
std::span<int> s = /*...*/;
// 使用下标
int first = s[0];
// 使用 front() 和 back()
int first = s.front();
int last = s.back();
// 使用迭代器
for (auto it = s.begin(); it != s.end(); ++it) {
// 处理 *it
}
// 范围 for 循环
for (int val : s) {
// 处理 val
}
4. 子视图操作
std::span<int> s = /*...*/;
// 获取前 N 个元素
auto first3 = s.first(3);
// 获取后 N 个元素
auto last2 = s.last(2);
// 获取子范围 [offset, offset + count)
auto sub = s.subspan(1, 3); // 从索引1开始,取3个元素
5. 其他常用操作
std::span<int> s = /*...*/;
// 获取大小
size_t size = s.size();
// 检查是否为空
bool empty = s.empty();
// 获取底层数据的指针
int* data = s.data();
// 获取字节大小
size_t bytes = s.size_bytes();
高级用法
1. 固定大小的 span
// 固定大小为5的span
std::span<int, 5> fixed_span(arr);
// 固定大小的span可以在编译期检查越界
// fixed_span[5] = 10; // 编译错误
2. 与标准算法一起使用
std::vector<int> vec = {5, 3, 1, 4, 2};
std::span<int> s(vec);
// 排序
std::sort(s.begin(), s.end());
// 查找
auto it = std::find(s.begin(), s.end(), 3);
3. 作为函数参数
void process_data(std::span<const int> data) {
// 只读访问data
}
void modify_data(std::span<int> data) {
// 可修改访问data
}
int main() {
std::vector<int> vec = {1, 2, 3};
process_data(vec);
modify_data(vec);
}
注意事项
std::span
不拥有其元素,它只是视图- 确保
std::span
的生命周期不超过底层数据 - 对于只读访问,使用
std::span<const T>
- 固定大小的
span
可以提供更好的编译时检查
std::span
是替代原始指针和大小对的一种更安全的方式,特别适合在函数间传递数组或连续容器数据。