Matching issues in New and Delete, Delete [] in C ++ (original)

zhaozj2021-02-16  57

This is a discussion I found when I was visiting online, the origin is <

> Some examples in a book. I checked some information and wrote my conclusion here. Let us first look at a more post, E text, patiently look.

Mismatching Scalar and Vector New and Delete

In a Previous Entry I Alluded to The Problems That Can Occur if you missch Scalar "New" with Vector

"delete []"

OR Vice Versa.

There is a nice description of C memory management in C Gotchas: Avoiding Common Problems in Coding and Design on www.informit.com, and I encourage you to read at least the section titled Failure to Distinguish Scalar and Array Allocation before continuing with this entry , Because I'm Going to Use That Information As a Starting Point.

Here's how the Microsoft C compiler manages vector allocation. Note that this is internal implementation detail, so it's subject to change at any time, but knowing this may give a better insight into why mixing scalar and vector new / delete is a bad thing.

The important thing to note is that when you do a scalar "delete p", you are telling the compiler, "p points to a single object." The compiler will call the destructor once, namely for the object you are destructing.

When you do

"delete [] p"

, You are saying, "p points to a bunch of objects, but I'm not telling you how many." In this case, the compiler needs to generate extra code to keep track of how many it needs to destruct. This extra information Is Kept in a "Secret Place" When the Vector Is Allocated with

"new []"

.

Let's Watch this in action:

Class myclass {public: myclass (); // constructor ~ myclass (); // destructor int i;}; myclass * allocate_stuff (int howmany) {return new myclass [howmany];

The generated code for the "allocate_stuff" Function Looks Like this: Push ESI MOV ESI, [ESP 8];

Howmany;

EAX = HOWMANY * SIZEOF (MyClass) Sizeof (size_t)

LEA EAX, [ESI * 4 4]

Push EAX

Call Operator New Test Eax,

EAX POP ECX JE FAIL PUSH EDI

Push offset myclass :: myclass

Push ESI LEA EDI, [EAX 4];

EDI = EAX SIZEOF (SIZE_T) PUSH 4;

Sizeof (MyClass) Push EDI MOV [EAX], ESI;

HOWMANY CALL `Vector CONSTRUctor Iterator 'MOV EAX,

EDI POP EDI JMP DONE FAIL: XOR Eax, Eax Done: POP ESI RETD 4

TRANSLATED Back Into Pseudo-C , The Code Looks Like this:

Myclass * allocate_stuff (int howmany)

{

Void * p = operator new (howmany * sizeof (myclass) sizeof (size_t));

IF (p)

{size_t * a = reinterpret_cast

(p);

* a = howmany; Vector Constructor Iterator (A, Sizeof (MyClass), & myclass :: myclass;

Return Reinterpret_cast_cast

(a);

}

Return NULL;

}

In Other Words, The Memory Layout of The Vector of Myclass Objects Looks Like this:

How ManmyClass [0] Myclass [1] ... myclass [howmany-1]

The Pointer Returned by THE

New []

Operator is not the start of the allocated memory [0]. The Count of Elements is Hidden in Front of the Vector.

The Deletion of a Vector Performs this Operation In Reverse:

Void free_stuff (myclass * p) {delete [] p;}

Generates

MOV ECX, [ESP 4];

P test ECX,

ECX JE SKIP PUSH 3

Call myclass :: `Vector deleding destructor` Skip Ret 4

TRANSLATED Back Into Pseudo-C , The Code Looks Like this:

Void Free_STUFF (MyClass * P)

{IF (p)

P-> Vector

DELETING DESTRUCTOR (3);

}

The Vector Deleting Destructor Goes Like this (pseudo-code):

Void Myclass :: Vector Deleting Destructor (int Flags)

{IF (Flags & 2) {//iff Vector Destruct

Size_t * a = reinterpret_cast

(THIS) - 1;

SIZE_T HOWMANY = * A;

Vector Destructor Iterator (p, sizeof (myclass), howmany,

Myclass :: ~ myclass;

IF (Flags & 1)

{// if delete TOO Operator

delete (a);

} else {// Else Scalar Destruct

this-> ~ myclass (); // destruct one

IF (Flags & 1)

{// if delete TOO Operator

Delete (this);

}

}

The Vector Deleting Destructor Takes Some Flags. IF 2 IS Set, THEN A Vector Is Being Destructed; Otherwise A Single Object Is Being Destructed. IF 1 IS Set, The Memory Is Also Freed.

In our case, the flags parameter is 3, so we will perform a vector destruct followed by a delete. Observe that this code sucks the original "howmany" value out of its secret hiding place and asks the vector destructor iterator to run the destructor that Many Times Before Freeing The Memory.

SO now, armed with this information, you shouth, you allocate memory with scalar "new" and free it with frees

"delete []"

Or Vice Versa. Answers To Come Tomorrow.

Bonus Exercise: What Optimizations Can Be Performed if The Destructor Myclass :: ~ myclass () is removed from the class definition?

After reading, two points touch, 1. The most painful of learning. 2. Look at things or e text well.

I think this post can make a conclusion: DELETE and DELETE [] are no different when Delete has an array of delete. When Delete is a group containing multiple elements, delete must be used. DELETE only has a role in the stack, and the delete variable does not work, and the memory of the variable is not released, and the value still exists. At the same time, DELETE [] NULL and DELETE NULL are safe, but the same non-NULL address delete is fatal.

When you delete a two-dimensional array, it should be:

For (int i = 0; i <10; i )

Delete P [i];

Delete [] P;

I don't know if the little brother is understanding, I hope that all prawn are correct.

转载请注明原文地址:https://www.9cbs.com/read-21008.html

New Post(0)