当RVO / NRVO启动时,是否复制了对象?

时间:2012-04-24 06:16:06

标签: c++ copy-constructor nrvo rvo

我无法理解RVO(和NRVO)定义因为多个问题like this one,我认为假设RVO省略了复制构造函数。现在根据12.8.15

  

在这种情况下,实现将省略的复制操作的源和目标视为仅仅两种不同的引用同一对象的方式,并且该对象的销毁发生在两个对象具有的时间的后期。没有优化就被摧毁了。

看起来并没有复制构造函数调用被忽略,但是复制本身 - 只是对象是在" copy"位于第一位,因此没有"原创"对象,根本没有复制。所以即使一个类有一个private拷贝构造函数,它也可以在RVO启动时从函数返回,因为它没有副本。

我能做对吗?复制本身是省略还是复制构造函数invokation被省略?当对象类具有私有拷贝构造函数时,是否应该允许从函数返回一个对象?

6 个答案:

答案 0 :(得分:8)

如果优化生效,则忽略复制,但仍需要编译器检查复制构造函数是否可访问。否则,如果编译器(或其他编译器)决定不进行优化,代码将无效。

答案 1 :(得分:7)

是否省略了复制本身或是否省略了复制构造函数invokation?

省略复制操作本身。如果你看一下完整的引用,就会明确提到:

C ++ 03 12.8复制类对象

第15段

  

当满足某些条件时,允许实现省略类对象的复制结构,即使该对象的复制构造函数和/或析构函数具有副作用。在这种情况下,实现将省略的复制操作的源和目标简单地视为引用同一对象的两种不同方式,并且在两个对象的后期发生对该对象的破坏。   如果没有优化,就会被销毁.111)在下列情况下可以省略复制操作(可以合并以消除多个副本):

     

- 在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象的名称时,复制操作可以通过将自动对象直接构造为函数的返回值来省略

     

- 当一个尚未绑定到引用(12.2)的临时类对象被复制到具有相同cv-nonqualified类型的类对象时,可以通过构造来省略复制操作临时对象直接进入省略副本的目标.....

当对象类有私有拷贝构造函数时,是否应该允许从函数返回一个对象?

RVO和NRVO是编译器优化,编译器允许但不能保证如果特定的哑编译器无法提供这些优化会发生什么?
如果没有可访问的复制构造函数,代码将在所有不需要的编译器上中断。鉴于复制构造函数应该是可访问的。

答案 2 :(得分:3)

正式,不,RVO / NRVO不会影响程序是否形成良好。该标准明确允许复制构造函数的任何副作用被省略,但仍然应该对复制构造函数进行访问检查。

但是,大多数编译器都不会对省略的复制构造函数进行访问检查,除非您要求尽可能严格地执行规则。我不是很确定,但我似乎记得曾经使用了一些跳过访问检查,即使你 要求严格遵守(但我不记得确定)。

编辑(纠正我认为在其他一些答案中表达的误解):

本标准一节中的段落旨在按顺序阅读。适用于某种情况的第一段中的要求始终适用。在这种情况下,省略副作用的许可在第15段中。然而,在第14段之前,我们看到:

  

如果隐式使用对象的复制构造函数或复制赋值运算符且无法访问特殊成员函数(第11条),则程序格式错误。

因此,我们只进入第15段(可以省略复制)如果已经通过了第14段中指定的访问检查。

答案 3 :(得分:2)

这是副本本身被省略。每当实际进行复制时,必须使用复制构造函数完成复制,但有几种情况允许编译器优化复制。

堆栈返回更大和非pod对象。调用者为对象准备一个空间,并将指向该空间的指针作为隐藏参数传递。被调用者将对象复制到该空间中。这里可以进行两项优化:

  1. 被调用者可以直接在返回空间中创建对象。编译器必须确保将返回该对象,即只返回该对象可能跟随的返回语句,并且插入的代码不得抛出。
  2. 如果将结果分配给变量,则调用者可以传递其地址而不是创建临时地址。这只能在变量被初始化或者效果与调用operator=没有区别时才能完成,基本上如果类型具有默认构造函数,析构函数和operator=

答案 4 :(得分:1)

  

是否省略了复制本身或是否省略了复制构造函数invokation?

这个想法是省略了复制构造函数,尽管如果不改变程序的语义,允许编译器共享内存。

  

当对象类具有私有拷贝构造函数时,是否应该允许从函数返回对象?

不,这是不允许的。 “它应该”很难说,但允许它可以让你做各种各样的恶作剧并打破封装。在C ++ 11中,您可以通过在返回中使用{}构造并移动构造该值来实现此目的。

答案 5 :(得分:0)

如果你看看这篇文章NRVO revealed in MSDN

您将看到没有复制的moneytructor被调用。