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

当无法执行RVO时,是否需要显式编写std::move?

RVO失效时,要不要显式用std::move?

咱们先从最基础的共识说起:绝对不要对单个局部命名对象的直接返回加std::move,因为这会直接阻止编译器做RVO(返回值优化)——这可是编译器能给你做的最划算的性能优化之一,能直接跳过复制/移动构造,把对象直接构造在目标内存里。

那回到你的核心问题:当确定RVO完全没法执行的时候,该怎么处理?我们结合C标准和《Effective Modern C》的内容来拆解清楚:

先看标准和权威书籍的规则

C++14的两阶段重载解析逻辑

当满足复制/移动操作的省略条件(但不适用于异常声明),且待复制对象由左值指定,或者return语句中的表达式是命名了最内层封闭函数或lambda表达式的函数体或参数声明子句中声明的自动存储期对象的(可能带括号的)id表达式时,选择复制构造函数的重载解析首先会将该对象当作右值来执行。如果第一次重载解析失败或未执行,或者所选构造函数的第一个参数不是该对象类型的右值引用(可能带cv限定),则会再次执行重载解析,将该对象当作左值考虑。
[注:无论是否会发生复制省略,都必须执行这种两阶段重载解析。它确定了当省略未执行时要调用的构造函数,且即使调用被省略,所选构造函数也必须可访问。——结束注]

简单翻译一下:如果你的return语句符合RVO的触发条件(比如直接返回一个局部命名对象),哪怕编译器最终没做RVO,它也会先尝试把这个对象当作右值来匹配构造函数——相当于自动帮你做了std::move的效果。

《Effective Modern C++》的补充说明

这本书里把这个规则说得更直白:只要满足RVO的条件,不管编译器最终做不做优化,要么直接省略复制/移动,要么就必须把返回的局部对象当作右值处理——也就是标准强制要求了“隐式std::move”的兜底行为。

你的示例代码到底发生了什么?

先修正一下你代码里的小笔误(移动构造的参数应该是Test&&,不是const Test&&),然后看这段代码:

#include <iostream>
#include <string>
struct Test {
    Test() {}
    Test(const Test& other) { std::cout << "Test(const Test&)" << std::endl; }
    Test(Test&& other) { std::cout << "Test(Test&&)" << std::endl; }
};
Test foo(int param) {
    Test test1;
    Test test2;
    return param > 5 ? std::move(test1) : test2;
}
int main() {
    Test res = foo(2);
}

你看到输出是Test(const Test&),原因很简单:这个return语句的表达式是条件运算符的结果,它完全不符合RVO的触发条件——RVO要求return的是单个的、直接命名的局部对象,而条件表达式的结果是一个“二选一”的表达式,编译器根本没法做RVO。

这时候,标准里的“隐式std::move”规则就不生效了:当param=2时,返回的是test2,它是一个左值,所以编译器只能调用复制构造函数;如果param>5,你显式加了std::move(test1),它变成右值,就会调用移动构造函数。

最终结论:什么时候该显式加std::move?

答案是:只有当你确定RVO完全无法触发的时候,才需要显式加std::move,分两种场景:

  1. 可以触发RVO的场景:比如return test;这种直接返回单个局部命名对象的情况,哪怕你觉得编译器可能不做优化,也别加std::move——标准已经兜底了,要么RVO,要么隐式转右值,你加了反而会直接阻止RVO。
  2. 无法触发RVO的场景:比如你的示例里用条件运算符返回两个对象之一,或者返回的是函数调用的结果、或者是某个表达式计算后的对象,这时候RVO完全没机会生效,显式给要返回的局部对象加std::move,就能触发移动构造,避免不必要的深拷贝。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:31:21