117 std::span


作者Lou Xiao, deepseek创建时间2025-04-02 17:44:58更新时间2025-04-02 17:44:58

1. 概述

std::span 是 C++20 引入的一个轻量级非拥有式容器视图,用于表示连续内存区域的引用。

1.1 基本特性

  • 非拥有式:不管理所引用内存的生命周期
  • 连续内存:只能表示连续内存序列(如数组、vector等)
  • 运行时或编译时大小:可以是固定大小或动态大小
  • 轻量级:通常实现为指针+大小的组合

1.2 主要用途

  • 函数参数传递(替代指针+大小或首尾迭代器对)
  • 统一处理不同类型的连续容器(数组、vector、array等)
  • 避免不必要的容器拷贝

2. 基本语法

2.1 头文件

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <span>

2.2 构造方式

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 // 从数组
2 int arr[] = {1, 2, 3};
3 std::span<int> s1(arr);
4
5 // 从vector
6 std::vector<int> vec = {1, 2, 3};
7 std::span<int> s2(vec);
8
9 // 从指针和大小
10 int* ptr = arr;
11 std::span<int> s3(ptr, 3);
12
13 // 从其他span的子范围
14 std::span<int> s4 = s1.subspan(1, 2);

3. 模板参数

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 template<
2 class T,
3 std::size_t Extent = std::dynamic_extent
4 > class span;

3.1 模板参数说明

  • T:元素类型
  • Extent:范围大小(默认为dynamic_extent表示动态大小)

3.2 固定大小span

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 std::span<int, 3> fixed_span(arr); // 必须恰好3个元素

4. 成员函数和操作

4.1 元素访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 s.front(); // 首元素
2 s.back(); // 末元素
3 s[0]; // 下标访问
4 s.data(); // 底层指针

4.2 容量查询

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 s.size(); // 元素数量
2 s.size_bytes();// 字节大小
3 s.empty(); // 是否为空

4.3 迭代器支持

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 s.begin();
2 s.end();
3 s.rbegin();
4 s.rend();

4.4 子视图操作

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 s.first<3>(); // 前N个元素(编译时大小)
2 s.first(3); // 前N个元素(运行时大小)
3 s.last<3>(); // 后N个元素
4 s.subspan(1, 2); // 从偏移1开始的2个元素

5. 使用场景

5.1 函数参数传递

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 void process(std::span<const int> data) {
2 for (int val : data) {
3 // 处理元素
4 }
5 }
6
7 // 可以接受各种连续容器
8 process(std::vector{1, 2, 3});
9 process(std::array{4, 5, 6});
10 process({7, 8, 9}); // 初始化列表

5.2 与C风格API互操作

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 void legacy_api(int* data, size_t size);
2
3 void wrapper(std::span<int> data) {
4 legacy_api(data.data(), data.size());
5 }

5.3 多维度视图

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 // 2D视图示例
2 void process_image(std::span<std::span<const Pixel>> image) {
3 for (auto row : image) {
4 for (auto pixel : row) {
5 // 处理像素
6 }
7 }
8 }

6. 注意事项

6.1 生命周期管理

  • span不拥有数据,必须确保底层数据在span使用期间有效
  • 避免返回局部变量的span

6.2 类型转换

  • 可以隐式转换为span<const T>
  • 不能从const转换为非const

6.3 性能

  • 通常编译为与原始指针相同的代码
  • 无运行时开销

7. 与类似工具比较

特性std::spanstd::string_viewstd::vector
拥有数据
可修改元素
连续内存
支持非字符类型

8. 示例代码

8.1 基本使用

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <span>
2 #include <vector>
3 #include <iostream>
4
5 void print(std::span<const int> values) {
6 for (auto v : values) {
7 std::cout << v << ' ';
8 }
9 std::cout << '\n';
10 }
11
12 int main() {
13 int arr[] = {1, 2, 3};
14 std::vector<int> vec = {4, 5, 6, 7};
15
16 print(arr); // 1 2 3
17 print(vec); // 4 5 6 7
18 print({8, 9, 10});// 8 9 10
19
20 auto sub = std::span(vec).subspan(1, 2);
21 print(sub); // 5 6
22 }

8.2 固定大小span

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 void process3(std::span<int, 3> data) {
2 // 只接受恰好3个元素的span
3 }
4
5 int main() {
6 int arr[3] = {1, 2, 3};
7 process3(arr); // OK
8
9 std::vector<int> vec = {1, 2, 3};
10 // process3(vec); // 错误:不能从动态span转换为固定span
11
12 std::array<int, 3> arr2 = {1, 2, 3};
13 process3(arr2); // OK
14 }

9. 最佳实践

  1. 优先使用span<const T>作为输入参数,除非需要修改数据
  2. 避免长期存储span,因为它不管理生命周期
  3. 考虑固定大小span在编译时已知大小的情况下
  4. 替代指针+大小参数,提高代码安全性和可读性
  5. 注意const正确性:不能从span<const T>转换为span<T>

std::span 常用 API 的整理表格

名称用途原型代码示例注释
构造函数创建 std::span 对象span() noexcept = default;
span(pointer ptr, size_type count);
std::span<int> s1;
std::span<int> s2(arr, 3);
默认构造空 span;或从指针和元素数量构造。
begin返回指向首元素的迭代器constexpr iterator begin() const noexcept;auto it = s.begin();类似容器的 begin()
end返回指向末尾的迭代器constexpr iterator end() const noexcept;for (auto& x : s) { ... }配合 begin() 实现范围遍历。
size返回元素数量constexpr size_type size() const noexcept;size_t n = s.size();返回当前 span 中的元素个数。
empty检查是否为空constexpr bool empty() const noexcept;if (s.empty()) { ... }等价于 size() == 0
operator[]访问指定位置的元素constexpr reference operator[](size_type idx) const;int x = s[0];不进行边界检查(类似数组)。
data返回指向底层数据的指针constexpr pointer data() const noexcept;int* p = s.data();直接访问原始数组指针。
front访问首元素constexpr reference front() const;int x = s.front();若为空则未定义行为。
back访问末尾元素constexpr reference back() const;int x = s.back();若为空则未定义行为。
subspan创建子视图constexpr span subspan(size_type offset, size_type count = dynamic_extent) const;auto sub = s.subspan(1, 2);返回从 offset 开始的 count 个元素的视图。
size_bytes返回存储的字节数constexpr size_type size_bytes() const noexcept;size_t bytes = s.size_bytes();等价于 size() * sizeof(element_type)
first获取前 N 个元素的视图constexpr span first(size_type count) const;auto first3 = s.first(3);count > size() 则未定义行为。
last获取后 N 个元素的视图constexpr span last(size_type count) const;auto last2 = s.last(2);count > size() 则未定义行为。

完整示例代码

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <span>
2 #include <iostream>
3
4 int main() {
5 int arr[] = {1, 2, 3, 4, 5};
6 std::span<int> s(arr); // 自动推导长度
7
8 // 遍历
9 for (auto x : s) { std::cout << x << " "; }
10
11 // 子视图
12 auto sub = s.subspan(1, 3); // {2, 3, 4}
13
14 // 访问元素
15 std::cout << "\nFirst: " << s.front() << ", Last: " << s.back();
16
17 // 原始指针
18 int* p = s.data();
19 }

关键注释

  1. 轻量级std::span 不拥有数据,仅作为视图。
  2. 边界安全operator[] 无边界检查,需用户保证安全。
  3. 动态/静态长度:支持编译时固定长度(span<int, 5>)或运行时动态长度(span<int>)。
文章目录