You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++按值传参会比const引用传参效率更高吗?

先明确:面试官对拷贝消除的认知存在边界错误

拷贝消除不是万能优化,它的适用场景在C++标准里写得非常明确,永远不会对已经存在的左值实参生效:

  • 只有当你传入的是纯右值临时对象(比如f1(std::vector<int>{1})这种直接在传参位置构造的临时量),编译器才有可能(C++17及之后对这类场景是强制)消除拷贝,直接在形参的内存位置构造对象。
  • 只要你传入的是有名字的、在调用方作用域后续还要使用的左值vector,编译器根本没有办法做拷贝消除——它必须生成拷贝构造的逻辑,否则f1形参析构的时候会把调用方正在用的vector的堆内存释放掉,直接造成悬空指针问题。

标准库的vector没有类似std::string的短值优化实现,哪怕只存1个int元素,拷贝也要走完整的堆内存分配 -> 元素拷贝 -> 函数退出时析构释放堆内存流程,这部分开销是内存级别的,和你在godbolt上看到f2多出来的2条寄存器mov指令比,差了至少两个数量级,你测出来const引用传参更快完全是符合预期的结果,不是测试误差。

你看到f2多两条mov的原因也很简单:const引用底层是通过指针实现的,f2需要先解引用拿到vector对象的起始地址,再读取size字段,所以多了两次寄存器操作,这点开销在现代CPU上确实可以忽略,远抵不上按值传参的堆操作成本。
就算你把benchmark::DoNotOptimize去掉,只要测试用例里传的是左值vector,拷贝消除就不可能触发,测试结果自然不会有变化。

另外补充一点:给按值传递的形参加const不会带来任何性能收益,这个const只是限制函数内部不能修改本地的参数副本,对拷贝构造、拷贝消除的逻辑没有任何影响。

传参方式选型的可靠依据

完全不需要靠猜测编译器的优化行为做选择,按函数的语义需求选就不会错:

  • 如果函数内部只需要读取参数内容、不需要保留参数的独立副本,无条件优先选const引用传参。这种写法没有任何额外的堆操作、拷贝、析构开销,不依赖任何编译器优化,在所有场景下性能表现都是稳定可预期的,也是C++的通用最佳实践。
  • 只有当函数内部明确需要持有一份参数的独立副本时(比如要把参数存入类成员、要修改参数且不能影响调用方的原始值),才考虑按值传参。这种场景下如果传入的是右值,按值传可以直接触发移动构造,比const引用传参后再内部拷贝的效率更高,但前提是你确实需要这份副本。
  • 绝对不要为了“等编译器做拷贝消除”给不需要副本的参数用按值传递,这种做法相当于把性能寄托在小概率触发的优化上,在最常见的左值传参场景下只会引入完全没必要的额外开销。

内容的提问来源于stack exchange,提问作者Gábor Ábrahám

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 08:18:27