我来自Java,其中有任何引用,所以我试图弄清楚c ++实例创建的基础。
Employee getEmp(int a) {
Employee local(a);
return local;
}
Employee myEmp = m.getEmp(10);
有3次员工实例化(没有RVO)是否正确?
1 - 创建本地副本
2 - 创建临时用于绑定到引用)
3 - 创建myEmp
为什么第2步需要?为什么不直接将本地复制到myEmp?
如果我只使用Ubuntu,我是否应该依靠RVO,我是否正确使用RVO只创建了两个实例(步骤2中不需要)?
谢谢!!!
答案 0 :(得分:3)
如果没有RVO/NRVO
和copy elision
,则会有一次调用Employee(int)
和两次调用copy c-tor
,一次调用返回,一次调用myEmp
。使用RVO
和copy elision
- 一次调用Employee(int)
,可能无需调用复制c-tor。
第二次调用没有copy elision
的复制构造函数是必须的,因为你想从另一个对象构建新对象(工作到copy c-tor
)。
答案 1 :(得分:2)
函数返回的语义是独立于你的定义 使用返回值:将返回的值复制到某处 当本地堆栈帧被破坏时,它不会消失。所以没有 RVO,在您的示例中,您有:
在堆栈框架中构造名为local
的局部变量
getEmp
。
复制调用者所在的返回对象的构造
将能够访问。通常,调用者为内存分配内存
在自己的堆栈框架中返回对象,并传递隐藏的参数
将此内存的地址发送给被调用的函数。 RVO或NRVO
允许编译器将此返回的对象“别名”为本地对象:in
你的情况,在传入的地址创建变量local
作为
隐藏参数,而不是在本地堆栈框架中。
返回后,返回的对象将被“使用”,然后被破坏 完整表达的结束。 如果这个用途是初始化本地 使用复制构造函数的变量,中间值可能是 省略掉;编译器将传递实际对象的地址 构造为被调用函数的隐藏参数。 (严格 说来,这不是NRVO,但它是相关的。)但是,其他用途, 不能被遗弃;如果返回的值用于赋值给 现有变量,例如,赋值运算符将需要a 对要分配的实例的引用。正式要求 因为大多数使用返回值,所以中间对象就在那里 不作为复制构造函数的参数。
最后,鉴于现代编译器技术,你可以指望 编译器系统地删除上面的第二个副本。第一份副本 (RVO或NRVO)可能稍微困难一些。我希望能看到它 系统地在如上所述的简单情况下:RVO随时有一个 单次返回临时和NRVO,只要有一次返回 它返回在最外层范围定义的命名变量 功能。 NRVO(在实践中也是RVO,虽然我不知道为什么) 如果函数中有多个返回值,则不太可能发生。