zoukankan      html  css  js  c++  java
  • 从汇编看c++中参数对象和局部对象的析构顺序

    下面是c++的源码:

    class X  {
    public:
       int i;
       int j;
       ~X() {}
        
    };
    void f(X x) {
      X x1;
      x.i = 1;
      x.j = 2;
        
    }
    int main() {
        f(X());
    }
        


    下面是main函数的汇编码:

    _main    PROC
    
    ; 15   : int main() {
    
        push    ebp
        mov    ebp, esp
        sub    esp, 8;为临时对象预留8byte空间,由于没有显示定义构造函数,
                  ;而且这种情况下编译器提供无用的默认构造函数,因此看不到构造函数的调用
    
    ; 16   :     f(X());
    
        mov    eax, DWORD PTR $T2560[ebp+4];将偏移临时变量的首地址4byte处内存中内容给eax,即将临时变量的成员变量j值给eax
        push    eax;将eax压栈
        mov    ecx, DWORD PTR $T2560[ebp];将临时变量首地址中的内容给ecx,即将临时变量中的成员变量i值给ecx
        push    ecx;将ecx压栈
                   ;上面四句创建了临时变量的一份拷贝,作为参数调用f
        call    ?f@@YAXVX@@@Z                ; 调用函数f
        add    esp, 8;将栈顶指针下移8byte,释放为参数对象的提供的栈空间
        lea    ecx, DWORD PTR $T2560[ebp];将临时对象的首地址给ecx
        call    ??1X@@QAE@XZ                ; 为临时对象调用析构函数
    
    ; 17   : }
    
        xor    eax, eax
        mov    esp, ebp
        pop    ebp
        ret    0
    _main    ENDP

    从上面可以看出,产生的临时对象在函数调用完成退出后才调用析构函数。

    下面是f函数的汇编码:

    ?f@@YAXVX@@@Z PROC                    ; f
    
    ; 9    : void f(X x) {
    
        push    ebp
        mov    ebp, esp
        sub    esp, 8;为局部对象x1预留8byte的空间
    
    ; 10   :   X x1;
    ; 11   :   x.i = 1;
    
        mov    DWORD PTR _x$[ebp], 1;把1写给参数对象首地址处,即把1写入参数对象的成员变量i
    
    ; 12   :   x.j = 2;
    
        mov    DWORD PTR _x$[ebp+4], 2;把2写入偏移参数对象首地址4byte处的内存,即把2写入参数对象的成员变量j
    
    ; 13   :     
    ; 14   : }
    
        lea    ecx, DWORD PTR _x1$[ebp];将局部变量x1的首地址给ecx
        call    ??1X@@QAE@XZ                ; 为x1调用析构函数
        lea    ecx, DWORD PTR _x$[ebp];将参数对象的首地址给ecx
        call    ??1X@@QAE@XZ                ; 为参数对象调用析构函数
        mov    esp, ebp
        pop    ebp
        ret    0
    ?f@@YAXVX@@@Z ENDP                    ; f
    ; Function compile flags: /Odtp
    _TEXT    ENDS
    ;    COMDAT ??1X@@QAE@XZ
    _TEXT    SEGMENT
    _this$ = -4                        ; size = 4
    ??1X@@QAE@XZ PROC                    ; X::~X, COMDAT
    ; _this$ = ecx
    
    ; 6    :    ~X() {}
    
        push    ebp
        mov    ebp, esp
        push    ecx
        mov    DWORD PTR _this$[ebp], ecx
        mov    esp, ebp
        pop    ebp
        ret    0
    ??1X@@QAE@XZ ENDP    

    从上面的代码可以看出,参数对象和局部对象都是在函数退出之前调用析构函数。并且参数对象在局部对象调用析构函数之后再调用自己的析构函数。

  • 相关阅读:
    XAF 有条件的对象访问权限
    XAF 顯示 UnInplace Report(設置自定義條件顯示報表,不是根據選擇ListView記錄條件顯示報表)
    XAF 如何自定义PivotGrid单元格显示文本?
    XAF 如何布局详细视图上的按钮
    XAF How to set size of a popup detail view
    XAF Delta Replication Module for Devexpress eXpressApp Framework
    XAF 帮助文档翻译 EasyTest Basics(基础)
    XAF 用户双击ListView记录时禁止显示DetailView
    XAF How to enable LayoutView mode in the GridControl in List Views
    XAF 如何实现ListView单元格批量更改?
  • 原文地址:https://www.cnblogs.com/chaoguo1234/p/3074417.html
Copyright © 2011-2022 走看看