You need to enable JavaScript to run this app. C++中右值直接传参产生拷贝是标准规定还是编译器行为?原因是什么?
优惠活动
大模型
产品
解决方案
定价
更多

C++中右值直接传参产生拷贝是标准规定还是编译器行为?原因是什么?

结论

你观察到的行为是C++语言规范明确规定的,不属于编译器自定义行为;拷贝没有被优化消除的核心原因是std::function的类型擦除中间层阻断了复制消除(copy elision)的适用条件。

原理说明
  • C++17版本起明确规定了强制复制消除的适用场景:只有当纯右值(prvalue,比如你代码里的Bar{})直接用于初始化同类型对象时,编译器才必须跳过拷贝/移动构造逻辑,直接在目标对象的内存地址完成构造。
  • 复制消除的前提是编译期就能确定「源临时对象和目标对象的内存地址可以直接重合」,无法跨间接调用层生效。

你代码中使用std::function<void(Bar)>存储lambda,std::function的实现依赖类型擦除技术:当你调用setter(Bar{})时,参数首先会被传给std::function的operator(),先在类型擦除的中间层构造一份参数实例,再转发给内部存储的lambda。编译器无法跨这个间接调用层,把你外层构造的Bar{}直接构造到lambda按值参数a的内存地址上,因此必须产生一次额外的移动/拷贝,这完全符合C++标准的要求。

测试结果验证

我们可以对应你给出的输出验证上述逻辑,以in-place then copy场景为例:

  1. 构造Bar{}临时纯右值传入setter
  2. std::function的中间层移动构造一份Bar对象转发给lambda参数a,mv_count +1
  3. lambda内执行bar = a触发拷贝赋值,cp_count +1
    最终结果为mv_count=1 cp_count=1,和你的测试输出完全匹配。
    如果你把std::function替换为直接调用lambda,就会发现复制消除正常生效,不会产生额外的移动/拷贝开销。

内容的提问来源于stack exchange,提问作者TigerChan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 12:15:04