In C ++/CLI, The gcnew keyword is used to indicate memory allocation on the hosting stack. to distinguish it from the previous pointer, replace it with ^ *. In terms of semantics, their differences are roughly as follows: 1.
Gcnew returns a handle.(Handle ), New returns the actual memory address. 2.
Gcnew objects are hosted by virtual machines. The new object must be managed and released by itself. Program From the employee's point of view, whether it is a handle or something else is always a reference to a memory address. In fact, we can all understand it as a pointer. next we will write a paragraph Code To test it.
Using namespace system; Ref class Foo {public: Foo () {system: Console: writeline ("foo: foo ");}~ Foo () {system: Console: writeline ("foo ::~ Foo ");} public: int m_ivalue;}; int _ tmain () {int * pint = new int; int ^ RINT = gcnew int; Foo ^ rfoo = gcnew Foo; delete rfoo; Delete RINT; Delete pint ;} |
The following figure shows the selected parts of the JIT compiled assembly code during debugging (note the red part ):
Int * pint = new int; 10000004c mov ECx, 4 00000051 call dword ptr ds: [03b51554h] 00000057 mov ESI, eax 00000059 mov dword ptr [esp + 18 h], ESI int ^ RINT = gcnew int; 10000005d mov ECx, 788ef9d8h 00000062 call fcfaf66c 00000067 mov ESI, eax 00000069 mov dword ptr [ESI + 4], 0 00000070 mov EDI, ESI Foo ^ rfoo = gcnew Foo; 00000072 mov ECx, 3b51768h 00000077 call fcfaf66c 0000007c mov ESI, eax 0000007e mov ECx, ESI 00000080 call dword ptr ds: [03b517ach] 00000086 mov dword ptr [esp + 1ch], ESI Delete rfoo; 0000008a mov EBX, dword ptr [esp + 1ch] 0000008e test EBX, EBX 00000090 je 000000a4 00000092 mov ECx, EBX 00000094 call dword ptr ds: [03fd0028h] 0000009a mov dword ptr [esp + 14 h], 0 000000a2 JMP 000000ac 000000a4 mov dword ptr [esp + 14 h], 0 Delete RINT; 000000ac mov edX, EDI 201700ae mov ECx, 788f747ch 000000b3 call fc8d20fd 000000b8 mov EBP, eax 000000ba test EBP, EBP 000000bc je 000000d0 000000be mov ECx, EBP 000000c0 call dword ptr ds: [03fd0020h] 000000c6 mov dword ptr [esp + 10 h], 0 000000ce JMP 000000d8 000000d0 mov dword ptr [esp + 10 h], 0 Delete pint; 000000d8 mov ECx, dword ptr [esp + 18 h] 201700dc call dword ptr ds: [03b51540h] |
First, let's look at the code for allocating memory. 1. Call the new method for allocating memory.
Int * pint = new int; 10000004c mov ECx, 4 00000051 call dword ptr ds: [03b51554h] |
As you can see, as in the previous vc6, the steps for allocating memory are as follows: 1. first put sizeof (INT) = 4 in ECx 2. call operator new to allocate 4 bytes 3. calling constructors ...... (This is not our focus) after successful allocation, the return address will be placed in eax. 2. Call the gcnew Method for allocation
Int ^ RINT = gcnew int; 2017005d mov ECx, 788ef9d8h 00000062 call fcfaf66c... Foo ^ rfoo = gcnew Foo; 00000072 mov ECx, 3b51768h 00000077 call fcfaf66c |
We can see that gcnew also puts a parameter in ECx and then calls a function to complete the allocation operation. Obviously, 0x788ef9d8 should be an address, not a value. We can see that gcnew creates two different types of variables, but the called function address is 0xfcfaf66c, and the two addresses stored in ECx are different. What exactly do these addresses represent? Like New, gcnew puts the return address in eax. We can directly view the memory block pointed by eax from the memory window. Aha, see? The memory block corresponding to this eax = 0x00f73404 is
0x00f73404 D8 F9 8e 78 00 00 00... |
Isn't that the value from mov to ECx? Recalling the analysis object layout written yesterday Article It is certain that this is the methodtable address. For this int, the next four bytes correspond to the rawdata that stores it, for example, if your Initialization is 4, the corresponding memory will change to D8 F9 8e 79 04 00 00. The analysis clearly shows that the methodtable pointer is stored in ECx. Then, we will analyze the corresponding call function, from the VM code, we can see that there are three global functions used to create Objects Based on methodtable, and methodtable itself also provides a member function allocate (), however, this member function also calls the following function: objectref allocateobject (methodtable * PMT) objectref allocateobjectspecial (methodtable * PMT) objectref fastallocateobject (methodtable * PMT) in which allocateob The ject also calls allocateobjectspecial to complete the work. Then we should call allocateobject or fastallocateobject. In our example, the two call addresses are the same, but if you write the code double ^ pdouble = gcnew double; what is the address at this time? Is it the same as Int? At present, I have not carefully studied whether this address corresponds to this type of methodtable: allocate () or the above three global functions. if it corresponds to methodtable: allocate (), so there should be a methodtable: fastallocate () in 2.0, otherwise it should be the corresponding global functions allocateobject and fastallocateobject. In a few days, you must take the time to study it. The following describes the corresponding delete function.
Delete pint; 000000d8 mov ECx, dword ptr [esp + 18 h] 000000dc call dword ptr ds: [03b51540h] is relatively simple, that is, input the address, and then call operator Delete to release class memory, will call the destructor |
The code for releasing the gcnew object is as follows:
Delete RINT; 201700ac mov edX, EDI 201700ae mov ECx, 788f747ch 201700b3 call fc8d20fd |
This is also relatively simple. It corresponds to a function in the VM: void callfinalizer (thread * finalizerthread, object * fobj), that is, fobj à edxfinalizerthread à ecxcall callfinalizer. However, please note !!!!!!! A class contains a destructor and does not contain a destructor. The Delete Code corresponding to the class is different. This can be obtained by comparing the assembly code. I will not talk about it here.