理解复制构造函数调用和命名返回值优化

时间:2016-06-24 05:23:38

标签: c++ copy-constructor copy-elision

我一直在研究有关NRVO的this文章。

  class RVO
  {
    public:
    RVO(){
          printf("I am in constructor\n"); }
    RVO(const RVO& c_RVO) { 
          printf("I am in copy constructor\n"); }
    ~RVO(){
          printf("I am in destructor\n"); }
    int mem_var;
  };
  RVO MyMethod(int i)
  {
     RVO rvo;
     rvo.mem_var = i;
     return (rvo);
  }
  int main()
  {
        RVO rvo;
        rvo=MyMethod(5);
  }

视觉工作室的输出如下,这就是我理解的方式

 I am in constructor       // main rvo construction
 I am in constructor       //MyMethod rvo construction 
 I am in copy constructor  //temporary created inside MyMethod
 I am in destructor        //Destroying rvo in MyMethod
 I am in destructor        //Destroying temporary in MyMethod
 I am in destructor        //Destroying rvo of main

如果我把主要写为

 int main()
 { 
    RVO rvo = MyMethod(5);
    return 0;
 }

输出如下以及如何理解

 I am in constructor       //MyMethod rvo construction 
 I am in copy constructor  //temporary created inside MyMethod
 I am in destructor        //Destroying rvo in MyMethod
 I am in destructor        //Destroying rvo of main

为什么在第二个版本的Mymethod中临时没有被销毁?

为什么复制构造函数没有在RVO rvo = MyMethod(5);中调用。我认为复制构造函数应该在第二个版本中调用两次,一个用于临时在Mymethod内创建,另一个用于RVO rvo = MyMethod(5); 我知道有些电话可能会被删除。有人可以帮忙解释这些电话。

编辑: 使用return rvo代替return (rvo)会将输出更改为

第一种情况

 I am in constructor
 I am in constructor
 I am in destructor
 I am in destructor

第二种情况

 I am in constructor
 I am in destructor       

我想当我删除括号时,NRVO会启动。但是当没有优化时我对第一个输出更感兴趣

2 个答案:

答案 0 :(得分:0)

第一个descructor调用是来自主要的rvo的解构。首先创建的对象必须删除。这不是复制作业,是复制构造。

答案 1 :(得分:0)

更新:使用return (rvo);而不是I am in constructor I am in constructor I am in destructor I am in destructor 来解决更新程序的输出

MyMethod::rvo

您看到这一点的原因是两个对象(main::rvothis)都经过默认构造,然后后者被分配为单独的操作但您没有记录它。< / p>

通过输出对象的地址可以更好地了解发生的事情,并且可以调用#include <cstdio> #include <iostream> class RVO { public: RVO(){ printf("%p constructor\n", this); } RVO(const RVO& c_RVO) { printf("%p copy constructor, rhs %p\n", this, &c_RVO); } ~RVO(){ printf("%p destructor\n", this); } int mem_var; }; RVO MyMethod(int i) { RVO rvo; std::cout << "MyMethod::rvo @ " << &rvo << '\n'; rvo.mem_var = i; return (rvo); } int main() { RVO rvo=MyMethod(5); std::cout << "main::rvo @ " << &rvo << '\n'; } 指针值作为函数:

cl /O2

输出还取决于您是否使用optimisations进行编译;您链接到Microsoft文档,所以也许您正在使用Microsoft编译器 - 尝试main

  

为什么在第二个版本的Mymethod中暂时没有销毁?

没有临时性 - 002AFA4C constructor MyMethod::rvo @ 002AFA4C // MyMethod::rvo's constructed 002AFA70 copy constructor, rhs 002AFA4C // above is copied to 2AFA70 002AFA4C destructor // MyMethod::rvo's destructed main::rvo @ 002AFA70 // turns out the copy above was directly to main::rvo 002AFA70 destructor // main::rvo's destruction 中的对象是直接复制构造的。引导你完成它:

002FF890 constructor  // we find out this is main::rvo below
002FF864 constructor  // this one's MyMethod::rvo
MyMethod::rvo @ 002FF864
002FF888 copy constructor, rhs 002FF864  // 2FF888 is some temporary
002FF864 destructor   // there goes MyMethod::rvo
002FF888 destructor   // there goes the temporary
main::rvo @ 002FF890
002FF890 destructor   // and finally main::rvo
  

[Alf下面的评论]&#34;直接复制构造&#34;对我来说并不完全有意义。我认为OP意味着rvo局部变量

考虑第一版程序的增强输出(无优化):

I am in constructor       // main rvo construction
I am in constructor       //MyMethod rvo construction 
I am in copy constructor  //temporary created inside MyMethod
I am in destructor        //Destroying rvo in MyMethod
I am in destructor        //Destroying temporary in MyMethod
I am in destructor        //Destroying rvo of main

如果我们将其重新绑定到OP的输出和注释......

main::rvo

OP(正确)将复制构造的对象称为临时对象。当我说到程序的第二个版本时,#34;那里没有临时版本 - main中的对象是直接复制构造的。&#34; - 我的意思是,我们在上面直接分析的第一个程序中没有临时等价物,而是MyMethod::rvo<button type="button" class="btn btn-primary close" href="#">Dismiss</button> 复制的{{1}}。