DsCpp
DsCpp

Reputation: 2489

Temporary object for by-value function creation scope

I have this following code which i can not understand:

#include <cstdio>
#include <iostream>

using namespace std;
class A 
{
    public: 
        int t = 0;
    A(){
      cout << "constructed"  << t<< endl; 
    } 
 A (A&& a) {

    cout << "in move ctor, moving"<< a.t << endl;
 }
 ~A() { 

     cout << "deleting"<< t << endl;
    }

};

A f1 (A a) 
{ 
    a.t = 1;
    std::cout << "f1: " << endl; 
    return a; 
}

int main() {
    A a = f1(A()) ;
    printf("what is happening\n");
}

and the output is

constructed0
in move ctor, moving0
f1: 
in move ctor, moving1
in move ctor, moving0
deleting0
deleting1
deleting0
what is happening
deleting0

The thing that I can not understand is the phase where the temporary object created for f1 (the one with a.t=1) is being destroyed.

From the output I assume it is being destroyed at the and of the line A a = f1(A()) ; While I thought it was created inside f1 and for f1, and therefore will be destroyed when exiting the function, before deleting0 is being called.

What am I missing?

Upvotes: 0

Views: 84

Answers (1)

DsCpp
DsCpp

Reputation: 2489

So after a bit research I have the Answer.

Here is the disassembly of the code (changed the move constructor to a copy constructor for readability):

int A::counter = 0;

A f1 (A a) 
{ 
  400a18:   55                      push   %rbp
  400a19:   48 89 e5                mov    %rsp,%rbp
  400a1c:   48 83 ec 10             sub    $0x10,%rsp
  400a20:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400a24:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
    cout << __LINE__ << endl;
  400a28:   be 1d 00 00 00          mov    $0x1d,%esi
  400a2d:   bf 80 13 60 00          mov    $0x601380,%edi
  400a32:   e8 c1 fd ff ff          callq  4007f8 <_ZNSolsEi@plt>
  400a37:   be 78 08 40 00          mov    $0x400878,%esi
  400a3c:   48 89 c7                mov    %rax,%rdi
  400a3f:   e8 24 fe ff ff          callq  400868 <_ZNSolsEPFRSoS_E@plt>
    a.t = 1;
  400a44:   48 8b 45 f0             mov    -0x10(%rbp),%rax
  400a48:   c7 00 01 00 00 00       movl   $0x1,(%rax)
    std::cout << "f1: " << endl; 
  400a4e:   be ce 0e 40 00          mov    $0x400ece,%esi
  400a53:   bf 80 13 60 00          mov    $0x601380,%edi
  400a58:   e8 fb fd ff ff          callq  400858 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
  400a5d:   be 78 08 40 00          mov    $0x400878,%esi
  400a62:   48 89 c7                mov    %rax,%rdi
  400a65:   e8 fe fd ff ff          callq  400868 <_ZNSolsEPFRSoS_E@plt>
    cout << __LINE__ << endl;
  400a6a:   be 20 00 00 00          mov    $0x20,%esi
  400a6f:   bf 80 13 60 00          mov    $0x601380,%edi
  400a74:   e8 7f fd ff ff          callq  4007f8 <_ZNSolsEi@plt>
  400a79:   be 78 08 40 00          mov    $0x400878,%esi
  400a7e:   48 89 c7                mov    %rax,%rdi
  400a81:   e8 e2 fd ff ff          callq  400868 <_ZNSolsEPFRSoS_E@plt>
    return a; 
  400a86:   48 8b 55 f0             mov    -0x10(%rbp),%rdx
  400a8a:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400a8e:   48 89 d6                mov    %rdx,%rsi
  400a91:   48 89 c7                mov    %rax,%rdi
  400a94:   e8 dd 01 00 00          callq  400c76 <_ZN1AC1ERKS_>
}
  400a99:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400a9d:   c9                      leaveq 
  400a9e:   c3                      retq   

0000000000400a9f <main>:

int main() {
  400a9f:   55                      push   %rbp
  400aa0:   48 89 e5                mov    %rsp,%rbp
  400aa3:   53                      push   %rbx
  400aa4:   48 83 ec 48             sub    $0x48,%rsp
    A a = f1(A()) ;
  400aa8:   48 8d 45 e0             lea    -0x20(%rbp),%rax
  400aac:   48 89 c7                mov    %rax,%rdi
  400aaf:   e8 2a 01 00 00          callq  400bde <_ZN1AC1Ev>
  400ab4:   48 8d 55 e0             lea    -0x20(%rbp),%rdx
  400ab8:   48 8d 45 d0             lea    -0x30(%rbp),%rax
  400abc:   48 89 d6                mov    %rdx,%rsi
  400abf:   48 89 c7                mov    %rax,%rdi
  400ac2:   e8 af 01 00 00          callq  400c76 <_ZN1AC1ERKS_>
  400ac7:   48 8d 45 c0             lea    -0x40(%rbp),%rax
  400acb:   48 8d 55 d0             lea    -0x30(%rbp),%rdx
  400acf:   48 89 d6                mov    %rdx,%rsi
  400ad2:   48 89 c7                mov    %rax,%rdi
  400ad5:   e8 3e ff ff ff          callq  400a18 <_Z2f11A>
  400ada:   48 8d 55 c0             lea    -0x40(%rbp),%rdx
  400ade:   48 8d 45 b0             lea    -0x50(%rbp),%rax
  400ae2:   48 89 d6                mov    %rdx,%rsi
  400ae5:   48 89 c7                mov    %rax,%rdi
  400ae8:   e8 89 01 00 00          callq  400c76 <_ZN1AC1ERKS_>
  400aed:   48 8d 45 c0             lea    -0x40(%rbp),%rax
  400af1:   48 89 c7                mov    %rax,%rdi
  400af4:   e8 31 02 00 00          callq  400d2a <_ZN1AD1Ev>
  400af9:   48 8d 45 d0             lea    -0x30(%rbp),%rax
  400afd:   48 89 c7                mov    %rax,%rdi
  400b00:   e8 25 02 00 00          callq  400d2a <_ZN1AD1Ev>
  400b05:   48 8d 45 e0             lea    -0x20(%rbp),%rax
  400b09:   48 89 c7                mov    %rax,%rdi
  400b0c:   e8 19 02 00 00          callq  400d2a <_ZN1AD1Ev>
    printf("what is happening\n");
  400b11:   bf d3 0e 40 00          mov    $0x400ed3,%edi
  400b16:   e8 ed fc ff ff          callq  400808 <puts@plt>
    cout << __LINE__ << endl;
    return a; 
}

The Copy constructor is called "ZN1AC1ERKS" after mangling process.
As we can see, the temporary object that is being created for f1, is being created before the function call, in main, and not as i expected, in f1's scope.

The meaning is as follows:
Temporary objects being created for functions that are called by value are not created in the functions scope, but rather on the line called the function, thus they will be destroyed before the next line execution, in the ordinary first created last destroyed way.

Upvotes: 1

Related Questions