C++同一表达式赋值前使用std::move的合法性与拷贝消除问题
问题1解答
编译器不允许自动执行这种隐式右值转换优化:
- C++标准仅在非常有限的场景下允许隐式将左值视为右值处理(比如函数返回局部非静态对象时的隐式移动),函数传参阶段不存在这类规则许可。
- 即使逻辑上y传参后立刻会被覆盖,编译器也受
as-if规则约束:如果std::string的拷贝/移动构造存在可观测的副作用,自动转换会改变程序可观测行为,因此主流GCC、Clang、MSVC在默认编译参数下都不会执行该操作。 - 你给出的原始代码中,
foo(y)调用一定会触发std::string的拷贝构造函数生成参数x,产生一次字符串内容的深拷贝。
问题2解答
y = foo(std::move(y))是完全合法的写法,且可以消除所有字符串深拷贝操作,整个过程的行为如下:
std::move(y)将左值y转为右值引用,foo的参数x通过std::string的移动构造函数初始化,仅转移内部字符串指针所有权,无深拷贝。- 此时原y进入「有效但值未指定」的状态,但后续你会立刻对y做赋值操作,不存在非法访问的风险,完全符合C++标准要求。
foo函数内修改x后返回时,要么触发NRVO优化直接将x构造在返回值存储位置,要么触发移动构造返回临时对象,无拷贝。- 最终将返回值赋值给y时调用移动赋值运算符,同样仅转移指针所有权,无深拷贝。
注意:这种写法仅在你确定移动后的原对象不会再被读取的前提下使用,本场景完全符合适用条件。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

