C++函数返回对象时使用std::move有何差异?
结论
别这么写,返回函数内部定义的非静态局部对象时显式套std::move是典型的画蛇添足,纯负优化,没有任何收益,还会堵死编译器的零开销优化路径。
两种写法的行为差异
先讲直接return message;的行为,这是C标准从C11开始就明确规定的规则:
当return的操作数是和函数返回类型完全匹配的非静态局部自动对象时,处理优先级分两层:
- 最高优先级是命名返回值优化(NRVO):编译器会直接在调用方接收返回值的内存地址上构造
message对象,全程既不拷贝也不移动,零额外开销,是最优结果。 - 如果因为多返回分支、编译选项关闭优化等原因NRVO无法生效,标准强制要求这里必须优先调用
MyObject的移动构造,只有类型没实现移动构造的时候,才会退化成拷贝构造。
再看return std::move(message);的行为:std::move会把message强转为右值引用,这时候返回的操作数不再是局部对象本身,而是对它的引用,直接不满足NRVO的触发条件,编译器会直接跳过返回值优化,强制调用一次移动构造把局部的message移到返回值空间。
你的认知误区
你以为“不加std::move就会触发对象拷贝,加了才会走移动”是完全错误的:
- 开O2等常规优化的生产编译场景下,直接返回的版本大概率触发NRVO,零复制开销;加了
std::move的版本反而要多执行一次移动构造,性能更差 - 哪怕NRVO触发失败,直接返回的版本也会默认走移动构造,和加
std::move的行为完全一致,不会多出来拷贝开销 - 唯一需要给返回值加
std::move的场景是返回函数形参(不是函数内部定义的局部变量),这种情况本来就触发不了NRVO,加std::move才会把拷贝改成移动,你现在的场景不属于这类。
注意:不要写依赖拷贝/移动构造副作用的代码,标准明确允许编译器在返回值优化场景下省略拷贝/移动构造的调用,靠加
std::move强制触发移动构造来跑副作用逻辑是完全错误的写法。
内容的提问来源于stack exchange,提问作者KansaiRobot
相关产品推荐
相关产品推荐

