C + + DELETE and delete []
Simple conclusion:
new Delete New [] delete [] Article:The declaration of Delete []void operator delete[] (void* ptr) throw (); void operator delete[] (void* ptr, const std::nothrow_t& nothrow_constant) throw (); void operator delete[] (void* ptr, void* voidptr2) throw (); A statement to Newvoid* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw ();
void* operator new (std::size_t size, void* ptr) throw ();
What is the problem with the following code--------------------------------------------------use the same form of new and delete?
std::string *stringarray = new std::string[100]; ... Delete Stringarray; |
Everything seems to be normal. A delete is also paired with new. However, there is still something completely wrong. The behavior of the program is undefined. Until finally, 99 of the 100 string objects pointed to by Stringarray are unlikely to be completely destroyed because their destructors may not have been called at all.
When you use a new expression (that is, create an object dynamically by using new), two things happen. First, allocate memory (via a function called operator new-see Item 49 and 51). Second, one or more constructors are called on these memory. When you use a delete expression (that is, using delete), there are two other things that happen: one or more destructors are called on these memory, and then the memory is recycled (via a function called operator delete-see Item 51). There is a big problem with delete: How many objects reside in the memory to be deleted? The answer to this question will determine how many destructors must be called.
In fact, the question is simple: is the pointer that will be deleted point to a single object or an array of objects? This is a critical issue because the memory layout of a single object is usually different from the memory layout of the array. In detail, the memory layout of an array usually contains the size of the array, which makes it easier to know how many destructors need to be called. This information is lacking in the memory of a single object. You can assume that different memory layouts look like, that n is the size of the array:
This is, of course, just an example. Compilers do not have to do this, though many are.
When you use Delete,delete on a pointer to know if there is an array size information, the only way is for you to tell it. If you add square brackets to the delete you are using, delete assumes that the pointer is pointing to an array. Otherwise, it is assumed to point to a single object.
std::string *stringptr1 = new std::string; std::string *stringptr2 = new std::string[100]; ... Delete stringPtr1; Delete an Object delete [] stringPtr2; Delete an array of objects |
If What happens when you use the [] form for STRINGPTR1? The result is undefined, but unlikely to be a good thing. Assuming a layout like this, delete reads the contents of some memory and considers it as an array size, and then begins to invoke so many destructors, not only ignoring the memory on which it works, but also forgetting the type of object it is busy deconstructing.
What happens if you don't use the [] form for STRINGPTR2? is undefined, but you don't see it causing too many destructors to be called. In addition, the result of a built-in type like int is undefined (and sometimes harmful), even if such a type does not have a destructor. The
rule is simple. If you use [] in the new expression, you must also use [] in the corresponding delete expression. If you do not use [] in the new expression, do not use [] in the matching delete expression.
When you write a class that contains a pointer to dynamically allocated memory, and you provide multiple constructors, this rule is especially important and should be engraved on your mind, because then you have to be careful to initialize that pointer member with the same form of new in all constructors. If you don't, how do you know what kind of delete should be used in your destructor?
This rule is also noteworthy for people with TypeDef tendencies, because it means that a typedef author must record in the document which form of delete should be used when generating an object of a TypeDef type with new. For example, consider this typedef:
typedef std::string ADDRESSLINES[4]; A person's address has 4 lines, Each of the which is a string |
Because Addresslines is an array, using new here,
std::string *pal = new Addresslines; Note that "New Addresslines" Returns a string*, just like "New String[4]" would |
You must match in the form of an array of delete:
Delete pal; undefined! delete [] pal; Fine |
To avoid this confusion, you should refrain from using TypeDef for the array type. That's simple, because the standard C + + library (see Item 54) contains string and vector, and those templates reduce the need to dynamically allocate arrays to almost zero. For example, here, Addresslines can be defined as a vector of string, that is, the type is vector.
Things to Remember
• If you are using [] in the new expression, you must use [] in the corresponding delete expression. If you do not use [] in the new expression, you do not have to use [] in the corresponding delete expression.
--------------------------------C + + DELETE, new, and New [], delete[] operator insider
People sometimes seem to like to deliberately make the C + + language's terminology difficult to understand. For example, the difference between the new operator (new operator) and operator new.
When you write such a code:
String *ps = new String ("Memory Management"); |
The new you are using is the new operator. This operator, like sizeof, is a language built-in, and you can't change its meaning, it always functions the same. The function it is to complete is divided into two parts. The first part is to allocate enough memory to accommodate the object of the desired type. The second part is that it calls the constructor to initialize the in-memory object. The new operator always does both things, and you can't change its behavior in any way.
What you can change is how to allocate memory for an object. The new operator calls a function to complete the required memory allocation, and you can override or reload the function to change its behavior. The name of the function called by the new operator for allocating memory is operator new.
The function operator new usually declares this:
void * operator new (size_t size); |
The return value type is void* because this function returns an unprocessed (raw) pointer to uninitialized memory. (If you like, you can write a operator new function that initializes memory to store some values before returning a pointer, but generally does not.) ) parameter size_t determines how much memory is allocated. You can add additional arguments to the overloaded function operator new, but the first parameter type must be size_t. (For more information about operator new, see effective C + + clause 8 to clause 10.) )
You don't normally call operator new directly, but once you do, you can invoke it like any other function:
void *rawmemory = operator new (sizeof (string)); |
The operator operator new returns a pointer to a piece of memory sufficient to hold a string object.
Just like malloc, operator New's responsibility is simply to allocate memory. It has no knowledge of the constructor function. Operator new is aware of memory allocations. Passing an unhandled pointer returned by operator new to an object is the work of the new operator. When your compiler encounters such a statement:
String *ps = new String ("Memory Management"); |
The code it generates is more or less similar to the following code (see effective C + + clause 8 and clause 10 for more details, as well as the comments in my article counting object. ):
void *memory =//Get unprocessed memory operator new (sizeof (string)); As a String object Call String::string ("Memory Management")//initialization On *memory; In memory
The object
String *ps =//Is the PS pointer pointing static_cast (memory); The new object |
Note that the second step contains the constructor call, which you do as a programmer is forbidden to do. Your compiler does not have this constraint, it can do everything it wants to do. So if you want to build a heap object you have to use the new operator and you cannot directly invoke the constructor to initialize the object.
Placement New
Sometimes you do want to call the constructor directly. It makes no sense to call a constructor on an existing object, because the constructor is used to initialize the object, and an object can be initialized only once given its initial value. But sometimes you have some (raw) memory that has already been allocated but not processed, and you need to construct an object in these memory. You can use a special operator new, which is called placement new.
The following example is how placement new is used, considering:
Class Widget { Public Widget (int widgetsize); ... };
Widget * Constructwidgetinbuffer (void *buffer,
int widgetsize) { return new (buffer) Widget (widgetsize); } |
This function returns a pointer to a Widget object that is allocated in the buffer that is forwarded to the function. This function may be useful when a program uses shared memory or memory-mapped I/O, because in such a program the object must be placed on a certain address or in memory allocated by the routine. (see article 4, a different example of how to use placement new.) )
Inside the Constructwidgetinbuffer, the returned expression is:
New (buffer) Widget (widgetsize)
This may seem strange at first, but it is a use of the new operator, which requires an extra variable (buffer), which is passed to the new operator when it implicitly calls the operator new function. The called operator new function must also accept the void* pointer parameter, in addition to the mandatory parameter size_t, to the memory space occupied by the construction object. This operator new is placement new, which looks like this:
void * operator new (size_t, void *location) { return location; } |
This may be easier than you expect, but that's what placement new needs to do. After all, the purpose of operator new is to allocate memory for an object and then return a pointer to that memory. In the case of placement new, the caller has obtained a pointer to memory because the caller knows where the object should be placed. What placement new has to do is return the pointer to it. (The unused (but mandatory) parameter size_t has no name to prevent the compiler from issuing a warning that it is not being used; see clause 6. Placement new is part of the standard C + + library. In order to use placement new, you must use the statement # # # (or if your compiler does not yet support this new style header file name).
Let's come back from placement new for a moment and see the new operator (new operator) in relation to operator new, you want to build an object on the heap, you should use the new operator. It allocates both memory and calls constructors for objects. If you just want to allocate memory, you should call the operator new function; it does not call the constructor. If you want to customize your memory allocation process when the heap object is built, you should write your own operator new function, then use the new operator, and the new operator will call your custom operator new. If you want to create an object in a piece of memory that has been given a pointer, you should use placement new.
Deletion and Memory deallocation
To avoid memory leaks, each dynamic memory allocation must correspond to a deallocation equivalent to the opposite. The relationship between the function operator delete and the delete operator is the same as the relationship of operator new with the new operator. When you see the code:
String *ps; ... Delete PS; Using the delete operator |
Your compiler generates code to deconstruct the object and release the memory that the object occupies.
Operator Delete is used to free memory, which is declared like this:
void operator delete (void *memorytobedeallocated); |
Therefore, delete PS;
Causes the compiler to generate code similar to this:
Ps->~string (); Call the object ' s Dtor operator delete (PS); Deallocate the memory
The object occupied |
One implication of this is that if you only want to handle uninitialized memory, you should bypass the new and delete operators, and call operator new to get memory and operator delete to free up memory to the system:
void *buffer =//Allocate sufficient operator New (50*sizeof (char)); Memory to hold 50 char
No constructor is called
... operator delete (buffer); Freeing memory
destructor not called |
This is equivalent to calling malloc and free in C.
If you are building an object in memory with placement new, you should avoid using the delete operator in that memory. Because the delete operator calls operator delete to free memory, but the memory that contains the object is not originally allocated by operator new, placement new simply returns the pointer that is forwarded to it. Who knows where this pointer comes from? Instead, you should explicitly call the object's destructor to remove the effect of the constructor:
Functions that allocate and free memory in shared memory void * mallocshared (size_t size);
void freeshared (void *memory); void *sharedmemory = mallocshared (sizeof (Widget)); Widget *PW =//As shown above, Constructwidgetinbuffer (Sharedmemory, 10); Use
Placement NEW
... Delete pw; The results are not sure! Shared Memory from Mallocshared, not operator new
Pw->~widget (); That's right. Deconstruct the widget that the PW points to,
But not released. Memory that contains widgets
freeshared (PW); That's right. Release the shared memory that PW points to
But no destructor is called |
As shown in the example above, if the raw memory passed to placement new is allocated dynamically (through some infrequently used methods), you must release it if you want to avoid a memory leak. (See my article counting objects for comments on placement Delete.) )
Arrays
Everything went well so far, but it had to go on. All we've tested so far is to build one object at a time. How do I allocate arrays? What's going to happen?
String *ps = new STRING[10]; Allocate an array of Objects |
The new operator is still used, but the behavior of the new operator is slightly different from the creation of a single object when an array is created. The first is that memory is no longer allocated with operator new, instead of an equivalent array allocation function called operator new[] (often referred to as array new). It can be overloaded like operator new. This allows you to control the memory allocation of the array as if you were able to control the memory allocations of individual objects (but there are some restrictive descriptions, see effective C + + clause 8).
(operator new[] is a relatively new thing for C + +, so your compiler might not support it. If it is not supported, regardless of the object type in the array, global operator new will be used to allocate memory for each array. Customizing array memory allocations under such a compiler is difficult because it requires overriding the global operator new. This is not an easy task to accept. By default, all dynamic memory allocations in the global operator new handler, so any changes to its behavior will have deep and pervasive implications. and the global operator new has a normal signature (normal signature) (also on a single parameter size_t, see effective C + + clause 9), so if you decide to declare it in your own way, You immediately make your program incompatible with other libraries based on these considerations, the array custom memory management is not a reasonable design in a compiler that lacks operator new[] support. )
The second difference is the number of constructors that the new operator calls. For arrays, the constructors for each object in the array must be called:
String *ps =//Call operator new[] is 10 New STRING[10]; The string object allocates memory,
Each array element is then called The default constructor for the string object. |
Similarly, when the delete operator is used for an array, it calls the destructor for each array element and then calls operator delete to free up memory.
Just as you can replace or reload operator delete, you also replace or reload operator delete[]. There are some limitations on the methods that they overload. Please refer to the excellent C + + textbook.
The new and delete operators are built-in, and their behavior is not controlled by you, and the memory allocation and deallocation functions they call can be controlled. When you want to customize the behavior of the new and delete operators, keep in mind that you can't really do that. You can only change the way they are used to accomplish their functions, and the functions they perform are fixed by the language and cannot be changed. (Can modify how they does what they does, but what they does is fixed by the language)
C + + DELETE and delete []