std::size最安全,C++17起支持栈上数组和容器,底层为sizeof(arr)/sizeof(arr[0])封装;函数参数中数组会退化为指针致其失效,需模板引用int(&)[N]推导长度。

用 std::size 最安全,C++17 起直接支持
对普通数组(非指针),std::size 是首选。它底层调用 sizeof(arr)/sizeof(arr[0]),但做了类型安全封装,且对容器也通用。
- 只适用于栈上定义的数组,比如
int arr[5];,不适用于int* arr = new int[5]; - 在函数参数中传入数组时会退化为指针,
std::size失效 —— 这是新手最常踩的坑 - 示例:
int a[] = {1, 2, 3}; static_assert(std::size(a) == 3); // ✅ 编译期确定
模板参数推导数组长度:靠引用 + sizeof 手动算
当必须把数组作为函数参数传入并获取长度时,只能靠模板 + 引用限定符阻止退化。
- 函数签名必须写成
template,void foo(int (&arr)[N]) (&arr)[N]表示“对 N 元素数组的引用” -
N会在编译期被自动推导,可用于返回、计算或static_assert - 错误写法:
void foo(int arr[])或void foo(int* arr)→ 完全丢失长度信息 - 示例:
template
size_t get_len(int (&)[N]) { return N; } int x[42]; auto n = get_len(x); // n == 42,类型安全,无运行时开销
为什么不能用 sizeof 在函数内部直接算?
因为数组一进函数就变指针,sizeof 返回的是指针大小(通常是 4 或 8),不是原数组大小。
- 现象:
void bad(int a[]) { std::cout → 输出 8(x64 下),不是原数组字节数 - 根本原因:C++ 标准规定,形参中的数组声明等价于指针声明,语法糖而已
- 连
decltype(a)都是int*,没有任何元信息残留
泛型场景下更推荐 std::array 或 std::span
如果控制不了调用方是否传原始数组,或需要真正泛型(兼容 std::vector、原始数组、C 风格字符串),优先用标准库容器视图。
立即学习“C++免费学习笔记(深入)”;
-
std::array自带.size(),且是聚合类型,可模板推导;但它要求编译期确定大小 -
std::span(C++20)能统一处理原始数组、std::vector、std::array,构造时自动捕获长度:std::span s{arr};→s.size()可用 - 注意:
std::span不拥有数据,仅是视图,别让它悬空
原始数组长度推导本质是编译期契约:你得让类型系统“看见”维度。一旦退化成指针,所有信息就不可逆地丢了。










