In depth analysis of the destructor timing of temporary objects in c++

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

In c++, once temporary objects are not needed, destructors are called to release the resources they possess. The named objects are called destructors in reverse of the order in which they were created.

C + + source code:


class X  {
public:
   int i;
   int j;
   ~X() {}
   X() {}

};
int main() {
    X x1;
    X();
    x1.i = 1;
    X x2;

    
}

Corresponding sink code:

_main    PROC
; 11   : int main() {
    push    ebp
    mov    ebp, esp
    sub    esp, 24                    ;  for x1  Temporary objects  x2 The reserved 24byte space 
; 12   :     X x1;
    lea    ecx, DWORD PTR _x1$[ebp]; To obtain x1 The first address of the object, passed as an implicit parameter to the constructor 
    call    ??0X@@QAE@XZ                ;  for x1 Call constructor 
; 13   :     X();
    lea    ecx, DWORD PTR $T2559[ebp]; Gets the first address of the temporary object and is passed to the constructor as an implicit parameter 
    call    ??0X@@QAE@XZ                ;  Call the constructor for the temporary object 
    lea    ecx, DWORD PTR $T2559[ebp]; Gets the first address of the temporary object and passes in the destructor as an implicit parameter 
    call    ??1X@@QAE@XZ                ;  A destructor is called for a temporary object 
; 14   :     x1.i = 1;
    mov    DWORD PTR _x1$[ebp], 1; will 1 Letter to x1 Memory at the first address, just about 1 write x1 Member variables in i In the 
; 15   :     X x2;
    lea    ecx, DWORD PTR _x2$[ebp]; To obtain x2 Is passed to the constructor as an implicit parameter 
    call    ??0X@@QAE@XZ                ;  for x2 Call constructor 
; 16   :     
; 17   :     
; 18   : }
    lea    ecx, DWORD PTR _x2$[ebp]; To obtain x2 Is passed in as an implicit argument to the destructor 
    call    ??1X@@QAE@XZ                ;  for x2 Call the destructor 
    lea    ecx, DWORD PTR _x1$[ebp]; To obtain x1 Is passed in as an implicit argument to the destructor 
    call    ??1X@@QAE@XZ                ;  for x1 Call the destructor 
    xor    eax, eax
    mov    esp, ebp
    pop    ebp
    ret    0
_main    ENDP

As you can see from the assembly code above, the temporary object does call the destructor after it is not needed, and even though it was created before the x2 object, it is still destructed before the x2 object. The order in which the x1, x2 destructors are called is the opposite of the order in which their constructors are called.

Now let's look at the following situation:

C++ source code:


class X  {
public:
  int i;
  int j;
  int k;
  X() {}
  ~X() {}
};

int main() {
    X x1;
    X(), x1.i = 1;//There is a comma operator
    X x2;
}

Here, after modifying the temporary object, there is a comma expression, not a semicolon.

The following is the assembly code:


; 12   : int main() {
    push    ebp
    mov    ebp, esp
    sub    esp, 36                    ;  for x1  Temporary objects  x2 The reserved 36 Byte space 
; 13   :     X x1;
    lea    ecx, DWORD PTR _x1$[ebp]; To obtain x1 Is passed to the constructor as an implicit parameter 
    call    ??0X@@QAE@XZ                ;  for x1 Call constructor 
; 14   :     X(), x1.i = 1;//There is a comma operator
    lea    ecx, DWORD PTR $T2560[ebp]; Gets the first address of the temporary object and is passed to the constructor as an implicit parameter 
    call    ??0X@@QAE@XZ                ;  Call the constructor for the temporary object 
    mov    DWORD PTR _x1$[ebp], 1; will 1 Assigned to x1 The memory at the first address is given x1 Member variable of i The assignment 1
    lea    ecx, DWORD PTR $T2560[ebp]; Gets the first address of the temporary variable and is passed to the destructor as an implicit parameter 
    call    ??1X@@QAE@XZ                ;  A destructor is called for a temporary object 
; 15   :     X x2;
    lea    ecx, DWORD PTR _x2$[ebp]; To obtain x2 Is passed to the constructor as an implicit parameter 
    call    ??0X@@QAE@XZ                ;  for x2 Call constructor 
; 16   : }
    lea    ecx, DWORD PTR _x2$[ebp]; To obtain x2 Is passed to the destructor as an implicit parameter 
    call    ??1X@@QAE@XZ                ;  for x2 Call the destructor 
    lea    ecx, DWORD PTR _x1$[ebp]; To obtain x1 Is passed to the destructor as an implicit parameter 
    call    ??1X@@QAE@XZ                ;  for x1 Call the destructor 
    xor    eax, eax
    mov    esp, ebp
    pop    ebp
    ret    0
_main    ENDP

As you can see, unlike the first time, the destructor is not called immediately after the temporary object is constructed, but after the assignment statement following the comma is executed.

In summary:

A temporary object calls a destructor when a high-level language is finished, and a semicolon marks the completion of a high-level language. So, a temporary object calls a destructor when it encounters a semicolon


Related articles: