返回本地还会涉及创建返回的临时值吗?

时间:2012-10-02 08:35:17

标签: c++

我来自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中不需要)?

谢谢!!!

2 个答案:

答案 0 :(得分:3)

如果没有RVO/NRVOcopy elision,则会有一次调用Employee(int)和两次调用copy c-tor,一次调用返回,一次调用myEmp。使用RVOcopy elision - 一次调用Employee(int),可能无需调用复制c-tor。

第二次调用没有copy elision的复制构造函数是必须的,因为你想从另一个对象构建新对象(工作到copy c-tor)。

答案 1 :(得分:2)

函数返回的语义是独立于你的定义 使用返回值:将返回的值复制到某处 当本地堆栈帧被破坏时,它不会消失。所以没有 RVO,在您的示例中,您有:

  1. 在堆栈框架中构造名为local的局部变量 getEmp

  2. 复制调用者所在的返回对象的构造 将能够访问。通常,调用者为内存分配内存 在自己的堆栈框架中返回对象,并传递隐藏的参数 将此内存的地址发送给被调用的函数。 RVO或NRVO 允许编译器将此返回的对象“别名”为本地对象:in 你的情况,在传入的地址创建变量local作为 隐藏参数,而不是在本地堆栈框架中。

  3. 返回后,返回的对象将被“使用”,然后被破坏 完整表达的结束。 如果这个用途是初始化本地 使用复制构造函数的变量,中间值可能是 省略掉;编译器将传递实际对象的地址 构造为被调用函数的隐藏参数。 (严格 说来,这不是NRVO,但它是相关的。)但是,其他用途, 不能被遗弃;如果返回的值用于赋值给 现有变量,例如,赋值运算符将需要a 对要分配的实例的引用。正式要求 因为大多数使用返回值,所以中间对象就在那里 不作为复制构造函数的参数。

  4. 最后,鉴于现代编译器技术,你可以指望 编译器系统地删除上面的第二个副本。第一份副本 (RVO或NRVO)可能稍微困难一些。我希望能看到它 系统地在如上所述的简单情况下:RVO随时有一个 单次返回临时和NRVO,只要有一次返回 它返回在最外层范围定义的命名变量 功能。 NRVO(在实践中也是RVO,虽然我不知道为什么) 如果函数中有多个返回值,则不太可能发生。