The detailed analysis of the destructional order of parameter objects and local objects in c++ is analyzed

  • 2020-04-01 23:33:10
  • OfStack

The following is the source of 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());
}


The following is the assembly code of the main function:

_main    PROC
; 15   : int main() {
    push    ebp
    mov    ebp, esp
    sub    esp, 8; Reserved for temporary objects 8byte Space, since the definition constructor is not shown, 
              ; And in this case the compiler provides a useless default constructor, so the constructor call is not seen 
; 16   :     f(X());
    mov    eax, DWORD PTR $T2560[ebp+4]; The first address of the temporary variable is offset 4byte The contents in memory are given eax , the member variable that is about to be a temporary variable j Values for eax
    push    eax; will eax The pressure of stack 
    mov    ecx, DWORD PTR $T2560[ebp]; Gives the contents of the first address of the temporary variable ecx , is a member variable in a temporary variable i Values for ecx
    push    ecx; will ecx The pressure of stack 
               ; The above four sentences create a copy of the temporary variable, called as a parameter f
    call    ?f@@YAXVX@@@Z                ;  Call a function f
    add    esp, 8; Move the top of the stack pointer down 8byte , freeing the stack space provided for the parameter object 
    lea    ecx, DWORD PTR $T2560[ebp]; Gives the first address of the temporary object ecx
    call    ??1X@@QAE@XZ                ;  A destructor is called for a temporary object 
; 17   : }
    xor    eax, eax
    mov    esp, ebp
    pop    ebp
    ret    0
_main    ENDP


As you can see above, the resulting temporary object does not call the destructor until the function call exits.

The following is the assembly code of f function:


?f@@YAXVX@@@Z PROC                    ; f
; 9    : void f(X x) {
    push    ebp
    mov    ebp, esp
    sub    esp, 8; Is a local object x1 The reserved 8byte The space of 
; 10   :   X x1;
; 11   :   x.i = 1;
    mov    DWORD PTR _x$[ebp], 1; the 1 Write to the first address of the parameter object 1 Writes a member variable to the parameter object i
; 12   :   x.j = 2;
    mov    DWORD PTR _x$[ebp+4], 2; the 2 Writes the first address of the offset parameter object 4byte In memory, that is to put 2 Writes a member variable to the parameter object j
; 13   :     
; 14   : }
    lea    ecx, DWORD PTR _x1$[ebp]; Local variables x1 The first address of ecx
    call    ??1X@@QAE@XZ                ;  for x1 Call the destructor 
    lea    ecx, DWORD PTR _x$[ebp]; Gives the first address of the parameter object to ecx
    call    ??1X@@QAE@XZ                ;  The destructor is called for the argument object 
    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

As you can see from the above code, both the argument object and the local object call the destructor before the function exits. And the argument object calls its own destructor after the destructor is called by the local object.


Related articles: