原生数组传参会退化为指针,丢失长度信息;std::array 不会退化,保持完整类型和尺寸。传参应使用 const std::array& 避免拷贝,模板推导需编译期确定 N。

std::array 传参不会退化,原生数组会
不会。std::array 是个聚合类模板,有完整类型信息,传值或传引用时都保持其维度和元素类型;而原生数组(如 int[5])一进函数就自动退化成指针(int*),丢掉长度信息。
常见错误现象:写 void f(int a[5]),以为能拿到长度,结果 sizeof(a) 是指针大小;换成 void f(std::array,a.size() 永远是 5,sizeof(a) 是 20(假设 int 为 4 字节)。
- 传值:拷贝整个对象,类型和大小都保留
- 传 const 引用:
const std::array最常用,避免拷贝且类型安全& - 千万别写
void f(std::array(N 未定义),编译不过——模板参数必须可推导或显式指定a)
怎么让函数接受任意尺寸的 std::array
靠模板参数推导。不能靠运行时,必须在编译期确定尺寸。
使用场景:写一个通用的打印函数、校验函数,不希望为每个尺寸重载一遍。
立即学习“C++免费学习笔记(深入)”;
正确写法:
templatevoid print(const std::array & arr) { for (const auto& x : arr) std::cout << x << ' '; }
- 参数类型必须是
const std::array或& std::array,不能省略N - 如果写成
std::array(C++20 起支持),仍需编译期可见尺寸,不能从std::vector或指针推 - 别试图用
std::span替代——它本身不保存尺寸,只是视图,和退化无关
为什么 std::array 不退化,但 sizeof 偶尔“看起来像退化”
因为 std::array 内部用原生数组作为成员(比如 T _M_elems[N]),某些编译器在调试信息或特定优化下可能让 sizeof 显示异常,但语义上绝无退化。
容易踩的坑:
- 误以为
std::array和原生数组一样,能在函数里用sizeof(arr)/sizeof(arr[0])算长度——它确实能算对,但这不是靠退化,而是靠成员数组的静态大小 - 把
std::array当作“更安全的 C 数组”来用,却忘了它仍是栈对象,大尺寸(如std::array)直接传值会爆栈 - 跨 DLL/so 边界传递
std::array时,ABI 兼容性依赖 STL 实现一致——比原生数组更脆弱
与原生数组混用时最常出错的点
直接把原生数组名传给期望 std::array 的函数,编译失败;反过来,把 std::array 的 .data() 传给只接受原生数组指针的 C 接口,是安全的,但要自己管长度。
- 错误示例:
void f(std::array→ 编译错,类型不匹配); int a[3] = {}; f(a); - 正确转换:
f(std::array或用构造函数(C++20 支持{a[0], a[1], a[2]}); std::to_array) -
std::array的.data()返回T*,和原生数组首地址等价,可安全传给printf("%d", *arr.data())这类 C 函数 - 别对
std::array取地址再强转成int(*)[5]——虽可行但没必要,且破坏类型安全
真正麻烦的是模板推导边界:比如你写了个 template,调用时 N 必须是字面量常量,不能是变量、constexpr 函数返回值(除非该函数被 constexpr 上下文完全求值),这点比原生数组的隐式退化更难调试。










