std::mdspan 是 c++23 引入的非拥有式多维数组视图,不管理内存,仅记录起始地址、维度大小和步长,支持自定义布局与访问器,适用于科学计算等场景。

std::mdspan 是 C++23 引入的核心新特性之一,用于提供对任意内存布局的多维数组的**非拥有式视图(view)**,类似 std::span 之于一维数组。它不管理内存,只记录起始地址、各维度大小和步长(stride),支持自定义布局(layout mapping)与访问器(accessor),灵活高效,特别适合科学计算、图像处理、线性代数库等场景。
基本用法:创建一个二维视图
最常见的是用默认布局 std::layout_right(行优先,类似 C 风格数组):
int data[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
std::mdspan<int, std::extents<int, 3, 4>> view(data); // 3×4 视图
// 等价写法(显式指定 layout)
std::mdspan<int, std::extents<int, 3, 4>, std::layout_right> view2(data);
std::cout << view(1, 2) << "\n"; // 输出 6(第1行第2列,0-indexed)
注意:std::extents 在编译期固定维度大小(如 <int></int> 表示 2D,大小分别为 3 和 4),也可用 dynamic_extent 表示运行时确定:
-
std::extents<int std::dynamic_extent></int>:第一维编译期为 3,第二维运行时传入 - 构造时需额外传尺寸:
std::mdspan<int std::extents std::dynamic_extent>> v(data, 4);</int>
自定义布局:列优先(Fortran 风格)
用 std::layout_left 实现列优先存储(即内存中按列连续):
立即学习“C++免费学习笔记(深入)”;
int data_col[12]; std::mdspan<int, std::extents<int, 3, 4>, std::layout_left> col_view(data_col); // col_view(i,j) 对应内存位置:base + i + j*3
你也可以实现自己的 layout mapping 类型,只要满足标准要求(提供 mapping::operator()() 和 stride() 等接口),适用于分块、对角、稀疏等特殊布局。
配合 accessor 实现带偏移或代理访问
默认 accessor 是 std::default_accessor,直接解引用指针。但你可以换用 std::submdspan 或自定义 accessor 来实现边界检查、缩放、只读、原子访问等:
- 安全访问(需自行实现或借助第三方封装,标准未提供内置 bounds-checking accessor)
- 只读视图:
std::mdspan<const int ...></const>已隐含只读语义 - 组合使用
std::submdspan切片子区域:auto sub = std::submdspan(view, std::tuple{1,3}, std::tuple{0,2});→ 取第1~2行、第0~1列
实际建议与注意事项
目前(GCC 13+ / Clang 16+ / MSVC 19.35+)已初步支持,但部分细节仍在完善。使用前注意:
- 确保编译器启用 C++23(
-std=c++23)且标准库支持 mdspan(如 libstdc++ ≥ 13.2,libc++ ≥ 16) - 避免把栈数组地址传给生命周期更长的 mdspan——它不拥有数据,易悬垂
- 维度数量不限于 2D,支持 1D 到 N 维(
std::extents<int></int>) - 想替代
std::vector<:vector>></:vector>?不行——后者是非连续内存;mdspan 要求底层是连续/可映射的内存块
std::mdspan 不是语法糖,而是为高性能数值计算设计的底层抽象。它把“形状”、“布局”、“访问”三者正交分离,让多维数组操作既安全又零成本。掌握它,就掌握了 C++23 在数据视图领域最关键的一步。











