用于按值函数创建范围的临时对象

时间:2018-01-10 17:32:43

标签: c++ scope

我有以下代码,我无法理解:

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

,输出

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

我无法理解的事情是临时对象为创建 f1(a.t = 1的那个)的阶段正在销毁。

从输出中我假设它在行A a = f1(A()) ;处被破坏虽然我认为它是在内部 f1和f1中创建的,因此在退出时会被销毁功能,之前正在调用.0。

我错过了什么?

1 个答案:

答案 0 :(得分:1)

经过一番研究后,我得到了答案。

以下是代码的反汇编(为了便于阅读,将移动构造函数更改为复制构造函数):

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

复制构造函数在修改过程后称为“ ZN1AC1ERKS ”。
正如我们所看到的,正在创建的 f1的临时对象正在函数调用之前创建,在main中,而不是在我预期的f1范围内。

含义如下:
为值调用的函数创建的临时对象不是在函数作用域中创建的,而是在称为函数的行上创建的,因此它们将在下一行执行之前被销毁,在普通的第一个创建的最后一个被破坏的方式中。