我有以下代码:
SomeClass func()
{
SomeClass someObject;
someObject.mutate("some text");
return someObject;
}
int main()
{
func();
return 0;
}
其中SomeClass仅在构造函数中记录一些内容,因此我可以验证正在调用的内容。
在发布版本中,我具有以下输出:
default constructor
由于复制/移动省略而有意义。 我想关闭“返回值优化”。 使用调试版本,我得到以下输出:
default constructor
move constructor
我认为我可以放心使用NRVO si。 我真的很想知道为什么调用move构造函数而不是copy构造函数。我的理解(可能是错误的)是,由于func中的someObject是一个左值,因此应该使用复制构造函数而不是move构造函数来初始化返回对象。
我想念什么?有人可以指出该情况的标准段落吗?
答案 0 :(得分:2)
从cppreference.com到return [expression];
:
如果
[expression]
是左值表达式,它是在正文中声明的自动存储期限对象的名称(可能带有括号),或者是最里面的封闭函数或lambda表达式的参数,则重载分辨率以选择用于初始化返回值的构造函数执行两次:首先,好像[expression]
是一个右值表达式(因此它可以选择move构造函数),并且如果没有合适的转换可用,或者如果第一个的类型所选构造函数的参数不是对对象类型的右值引用(可能是cv限定的),第二次执行重载解析,将[expression]
视为左值(因此它可以选择复制构造函数作为引用到非常量)。
简而言之,从C ++ 11开始,return
语句将在可能的情况下更喜欢使用move构造函数,并回退到copy构造函数。
答案 1 :(得分:0)
同样来自C ++ 11标准, 12.8复制和移动对象,第285页,项目32:
满足或将要满足复制操作的省略标准时,除以下事实外: object是一个函数参数,要复制的对象由左值,重载分辨率指定为 选择该副本的构造函数时,首先要执行该对象,就好像该对象是由右值指定的一样。如果超载 解析失败,或者所选构造函数的第一个参数的类型不是右值引用 对象的类型(可能是cv限定),则将对象视为 左值。 [注意:无论是否使用复制省略,都必须执行此两阶段重载解决方案 发生。它确定是否执行省略时要调用的构造函数,以及选定的构造函数 即使呼叫被取消也必须可以访问。 —尾注]