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