应优先使用 const std::array& 传递编译期已知大小的数组,避免值传递导致的整块拷贝;运行时大小数组用 std::span;std::vector 一律用 const std::vector&;C 风格数组用模板推导引用 int (&arr)[N]。

用 const std::array<t n>&</t> 传固定大小数组
编译期已知大小的数组,直接值传递会整块拷贝——比如 std::array<int></int> 拷贝一次就是 4KB。改用 const std::array<int>&</int>,只传地址,零拷贝开销,且保留完整类型信息(尺寸、元素类型),编译器还能做边界检查和内联优化。
常见错误是写成 std::array<int></int>(无引用)或退化为裸指针 int*(丢失长度、类型不安全)。
- 必须加
const&,否则无法绑定临时对象或字面量数组 - 不能省略模板参数
N,否则类型不匹配,编译失败 - 比 C 风格数组
int arr[1024]更安全:不会衰减为指针,.size()可用
用 std::span<const t></const> 传运行时大小的栈/堆数组
当数组大小在运行时才确定(比如函数接收一个局部大缓冲区或 std::vector 的数据),std::span 是最轻量又安全的选择。它不拥有数据,只持有一个指针 + 长度,构造开销是 O(1),且能自动推导长度(如传入 std::vector 或 C 数组)。
错误做法是用 std::vector<t></t> 值传递,或手写 T* + size_t 组合——前者触发深拷贝,后者易越界、无类型保护。
立即学习“C++免费学习笔记(深入)”;
- 传
std::vector数据:用std::span<const int>(vec.data(), vec.size())</const> - 传 C 数组:直接
std::span<const int>(arr)</const>,编译器自动推导长度 - C++20 起支持,GCC 10+/Clang 9+;若环境不支持,可用
gsl::span替代
避免 std::vector 值传递,优先用 const std::vector<t>&</t>
很多人误以为 std::vector 是“轻量容器”,其实它的值传递会触发完整的深拷贝:分配新内存 + 逐元素复制 + 析构旧副本。哪怕只含 1000 个 int,每次调用也多出约 4KB 内存操作。
正确做法始终是 const std::vector<t>&</t>——既避免拷贝,又明确表达“只读”语义,编译器也能据此做更多优化(如向量化访问)。
- 不要用
std::vector<t>*</t>:空指针风险高,接口不直观 - 不要用
std::vector<t>&&</t>除非你真要移动它——多数场景只是读取 - 若函数内部需修改副本,显式拷贝:
auto local = data;,把拷贝意图写清楚
模板参数推导数组引用:template<size_t n> void f(int (&arr)[N])</size_t>
对纯 C 风格数组(如 int buf[4096]),这是最底层、最高效的传参方式。编译器在调用点直接推导 N,生成特化函数,连 std::span 的构造开销都省了,且数组长度成为编译期常量,可用于栈分配、static_assert 校验等。
典型坑是写成 void f(int arr[]) 或 void f(int* arr)——这会让数组完全衰减,失去所有尺寸信息,变成不安全的裸指针。
- 必须用引用语法
int (&arr)[N],括号不能少,否则变成“数组指针”类型 - 适用于嵌入式、高性能计算等对每纳秒都敏感的场景
- 不能用于
new int[N]分配的堆数组——它不是“数组类型”,而是指针
实际项目里最容易被忽略的是:同一份数据在不同层级接口中混用多种传参方式,比如上层用 std::span,下层又转成 std::vector 值传递。这种隐式转换会悄悄引入拷贝,性能损耗叠加后很难排查。统一约定接口契约(比如“所有只读大数组输入一律用 std::span<const t></const>”),比单点优化更重要。


















