禁用RVO后返回局部对象为何调用move构造函数而非copy构造函数?
为什么返回局部左值时调用了移动构造而非拷贝构造?
问题描述
我定义了包含各类构造函数(默认、拷贝、移动)及赋值运算符的Snitch结构体,编写ReturnObj函数返回局部对象snit,在main函数中通过拷贝初始化接收返回值。使用g++ -fno-elide-constructors禁用RVO编译运行后,输出显示返回snit时调用了移动构造函数,但snit是局部左值,按预期应该调用拷贝构造函数初始化临时对象。我疑惑的是:这个局部对象在这里被当成xvalue了吗?
解答
这是C++标准规定的特殊规则:当return语句中的表达式是函数体内定义的非静态局部对象(且不是函数参数)时,即便它是左值,编译器也会自动将其视为亡值(xvalue),优先匹配移动构造函数。
本质上,这个规则是基于对象的生命周期——该局部对象在函数返回后马上就会被销毁,移动它不会产生任何安全问题,因此标准允许编译器优先选择更高效的移动构造。
你禁用RVO只是关闭了返回值优化,但这个“局部返回对象自动转为可移动”的规则依然生效,所以最终调用的是移动构造函数。
如果需要强制调用拷贝构造,可以通过std::as_const显式将其转为const左值:
return std::as_const(snit);
这样编译器就只能匹配拷贝构造函数。
内容的提问来源于stack exchange,提问作者Wason
相关产品推荐
相关产品推荐

