3

I have been looking into this article about NRVO.

  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);
  }

The output is the following on visual studio and this is how i understand it

 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

If instead i write the main as

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

The output is the following and how understand it

 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

Why is temporary not destroyed in Mymethod in the second version?

Why is copy constructor not called in RVO rvo = MyMethod(5);.I think copy constructor should be called twice in second version, one for the temporary created inside Mymethod and the other for RVO rvo = MyMethod(5); I know some call may be getting elided.Can someone please help in explaining these calls.

EDIT: Using return rvo instead of return (rvo) changes the output as

First case

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

second case

 I am in constructor
 I am in destructor       

I guess when i removed the parenthesis, then NRVO kicks in.But i am more interested in the first output when there is no optimization

4

2 回答 2

0

第一个析构函数调用来自 main 中 rvo 的析构函数。首先创建的对象必须被删除。完成的不是复制分配,而是复制构造。

于 2016-06-24T05:27:16.320 回答
0

UPDATE:处理更新程序的输出,使用return rvo而不是return (rvo);

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

您看到这一点的原因是两个对象 (MyMethod::rvomain::rvo) 都经过默认构造,然后将后者作为单独的操作分配给,但您没有记录它。


通过输出对象的地址,您可以更好地了解正在发生的事情,并将this指针值作为函数调用:

#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';
  }

输出还取决于您是否使用优化进行编译;您链接到 Microsoft 文档,因此您可能正在使用 Microsoft 编译器 - try cl /O2

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

那里没有临时的——里面的对象main是直接复制构造的。逐步引导您:

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

[下面阿尔夫的评论]“直接复制构建”对我来说并不完全有意义。我认为 OP 意味着 rvo 局部变量

考虑程序第一个版本的增强输出(没有优化):

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

如果我们将其与 OP 的输出和注释联系起来......

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 中的对象是直接复制构造的。” - 我的意思是在我们上面直接分析的第一个程序中没有临时等价物,而是main::rvoMyMethod::rvo.

于 2016-06-24T05:34:48.437 回答