究竟什么是在C ++中调用的析构函数

时间:2014-07-24 07:33:56

标签: c++

考虑以下代码

int i;

class A
{
public:
   ~A()
   {
       i=10;
   }
};

int foo()
{
   i=3;
   A ob;
   return i;
}

int main()
{
   cout << foo() << endl;
   return 0;
}

由于i是全局的,我认为该程序的输出应为10ob,当它超出范围时,将调用析构函数,该析构函数应将i的值设置为10

5 个答案:

答案 0 :(得分:16)

局部变量超出范围,并且在函数返回后执行它们的析构函数。这意味着,在~A()运行时,返回值已经为3。相反,如果你这样做......

int foo()
{
   {
      i=3;
      A ob;
   }
   return i;
}

... ob将超出范围并在return语句之前死亡,结果将为10。

对于像scoped_lock这样的RAII活动类型,通常以这种方式使用额外的范围,以仅针对函数的一部分进入某种特定的副作用状态。

答案 1 :(得分:7)

int foo()
{
   i=3;
   A ob;
   return i;
} // <- ~A() is called here
~A()超出范围时,在函数foo()的末尾调用

ob。这是在计算返回值之后(即i的副本,当时的值为3

为了在函数退出之前将i设置为10,您需要强制ob更早超出范围&#34;。最简单的是在A ob附近添加一个额外的范围。

int foo()
{
   i=3;
   {
     A ob;
   } // <- ~A() is called here and sets i to 10
   return i;
}

答案 2 :(得分:4)

返回执行后,

ob超出范围。考虑如果ob参与评估返回表达式会发生什么,并且在返回之前它会超出范围。

答案 3 :(得分:4)

ob在范围结束之前不会超出范围,即在}语句之后发生的return。这就是析构函数被调用的时候,但到那时i已被评估,所以它的旧值被返回。

答案 4 :(得分:3)

~A()超出范围时调用ob。 装配证明:

<__Z3foov>:
    push   %ebp
    mov    %esp,%ebp
    push   %ebx
    sub    $0x10,%esp
    movl   $0x3,0x407020        /* <-- setting i to 3 */
    mov    0x407020,%ebx        /* <-- loading i to %ebx */
    lea    -0x5(%ebp),%eax
    mov    %eax,%ecx
    call   403860 <__ZN1AD1Ev>  /* <-- calling destructor */
    mov    %ebx,%eax            /* <-- returnign already calculated i from %ebx */
    add    $0x10,%esp
    pop    %ebx
    pop    %ebp
    ret  

<__ZN1AD1Ev>:               /* <-- the destructor */
    push   %ebp
    mov    %esp,%ebp
    sub    $0x4,%esp
    mov    %ecx,-0x4(%ebp)
    movl   $0xa,0x407020    /* <-- set i to 10 */
    leave  
    ret  

正如您所看到的,在将返回值放入%ebx之后调用析构函数,当析构函数完成时,它再次移动到%eax。对于您将来有关C ++代码行为的问题,反汇编是您最好的朋友。