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) → 完全丢失长度信息templatesize_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 下),不是原数组字节数
decltype(a) 都是 int*,没有任何元信息残留std::array 或 std::span
如果控制不了调用方是否传原始数组,或需要真正泛型(兼容 std::vector、原始数组、C 风格字符串),优先用标准库容器视图。
std::array 自带 .size(),且是聚合类型,可模板推导;但它要求编译期确定大小std::span(C++20)能统一处理原始数组、std::vector、std::array,构造时自动捕获长度:std::span s{arr}; → s.size() 可用std::span 不拥有数据,仅是视图,别让它悬空原始数组长度推导本质是编译期契约:你得让类型系统“看见”维度。一旦退化成指针,所有信息就不可逆地丢了。