Sometimes people seem to like to deliberately make the terms in the C ++ language hard to understand. For example, the difference between the new operator and operator new.
When you write this Code:
String * PS = new string ("Memory Management ");
You use the new operator. This operator is just like sizeof which is built in a language. You cannot change its meaning and its functions are always the same. The functions to be completed are divided into two parts. The first part is to allocate enough memory to accommodate the required types of objects. The second part is that it calls the constructor to initialize objects in the memory. The new operator always does these two things, and you cannot change its behavior in any way.
What you can change is how to allocate memory to objects. The new operator calls a function to complete the necessary memory allocation. You can rewrite or reload the function to change its behavior. The new operator indicates that the name of the function called for memory allocation is Operator new.
The operator new function is usually declared as follows:
Void * operator new (size_t size );
The return value type is void *, because this function returns an unprocessed (raw) pointer with uninitialized memory. (If you like it, you can write an operator new function. Before returning a pointer, You can initialize the memory to store some values, but this is generally not the case .) The size_t parameter determines how much memory is allocated. You can add an extra parameter to overload the function operator new, but the first parameter type must be size_t. (For more information about operator new, see invalid tive C ++ clauses 8 to 10 .)
You generally do not directly call operator new, but once you do so, you can call it like calling other functions:
Void * rawmemory = Operator new (sizeof (string ));
The operator new returns a pointer pointing to a memory sufficient to accommodate a string type object.
Like malloc, operator new only allocates memory. It knows nothing about constructors. Operator new understands memory allocation. It is the work of the new operator to pass the unprocessed pointer returned by operator new to an object. When your compiler encounters such a statement:
String * PS = new string ("Memory Management ");
The code generated by it is more or less similar to the following code (for more details, see article 8 and article 10 of Objective C ++, as well as comments in my article counting object .) :
Void * Memory = // get unprocessed memory
Operator new (sizeof (string); // String object
Call string: string ("Memory Management") // Initialization
On * memory; // memory in progress
// Object
String * PS = // PS pointer
Static_cast (Memory); // new object
The second step involves calling constructor. You are not allowed to do this as a programmer. Your compiler does not have this constraint. It can do everything it wants. Therefore, if you want to create a heap object, you must use the new operator and cannot directly call the constructor to initialize the object.
Placement new
Sometimes you really want to call the constructor directly. Calling a constructor on an existing object is meaningless, because the constructor is used to initialize the object, and an object can only be initialized once when it is given an initial value. But sometimes you have some (raw) memory that has been allocated but not yet processed, You need to construct an object in the memory. You can use an extraordinary operator new called Placement new.
The following example shows how to use placement new. Consider the following:
Class widget {
Public:
Widget (INT widgetsize );
...
};
Widget * constructwidgetinbuffer (void * buffer,
Int widgetsize)
{
Return new (buffer) widget (widgetsize );
}
This function returns a pointer pointing to a widget object, which is allocated in the buffer transferred to the function. This function may be useful when the program uses shared memory or memory-mapped I/O, in such a program, objects must be placed in a fixed address or a memory allocated by the routine. (See Clause 4. A different example of how to use placement new .)
In constructwidgetinbuffer, the returned expression is:
New (buffer) widget (widgetsize)
This seems a little unfamiliar at the beginning, but it is a usage of the new operator and requires an additional variable (buffer). When the new operator implicitly calls the operator new function, pass this variable to it. In addition to the mandatory size_t parameter, the called operator new function must also accept the void * pointer parameter, pointing to the memory space occupied by the constructor. This operator new is placement new, which looks like this:
Void * operator new (size_t, void * location)
{
Return location;
}
This may be simpler than you expected, but this is what placement new needs to do. The purpose of operator new is to allocate memory to the object and then return a pointer to the memory. When placement new is used, the caller has obtained a pointer to the memory, because the caller knows where the object should be placed. What placement new must do is return the pointer to it. The size_t parameter (useless (but mandatory) has no name to prevent the compiler from issuing a warning that it is not in use. See Clause 6 .) Placement new is part of the standard C ++ library. To use placement new, you must use the statement # include (Or assume that your compiler does not support this new style of header file names ).
Let's take a moment back from placement new to see the relationship between the new operator and operator new. To create an object on the stack, you should use the new operator. It allocates both memory and calls constructors for objects. If you only want to allocate memory, you should call the operator new function; it will not call the constructor. If you want to customize your memory allocation process when the heap object is created, you should write your own operator new function and then use the new operator, the new operator calls your customized operator new. If you want to create an object in a memory with obtained pointers, you should use placement new.
Deletion and memory deallocation
To avoid Memory leakage, each dynamic memory allocation must correspond to an equivalent deallocation. The relationship between the operator Delete and delete operators is the same as that between operator new and new operators. When you see the code:
String * pS;
...
Delete pS; // use the delete Operator
Your compiler will generate code to analyze the object and release the memory occupied by the object.
Operator Delete is used to release memory. It is declared as follows:
Void operator Delete (void * memorytobedeallocated );
Therefore, delete pS;
The compiler generates code similar to this:
PS-> ~ String (); // call the object's dtor
Operator Delete (PS); // deallocate the memory
// The object occupied
This implies that if you only want to process uninitialized memory, you should bypass the new and delete operators and call operator new to obtain the memory and operator Delete to release the memory to the system:
Void * buffer = // allocate enough
Operator new (50 * sizeof (char); // memory to accommodate 50 char
// No constructor is called
...
Operator Delete (buffer); // releases memory
// The Destructor is not called.
This is equivalent to calling malloc and free in C.
If you use placement new to create an object in the memory, you should avoid using the delete operator in the memory. Because the delete operator calls operator Delete to release memory, but the memory containing objects is not initially allocated by operator new, placement new is just a pointer to it. Who knows where the pointer comes from? Instead, you should explicitly call the object's destructor to relieve the constructor's impact:
// Function void * mallocshared (size_t size) for allocating and releasing memory in the shared memory );
Void freeshared (void * Memory );
Void * sharedmemory = mallocshared (sizeof (widget ));
Widget * PW = // As shown above,
Constructwidgetinbuffer (sharedmemory, 10); // use
// Placement new
...
Delete PW; // The result is unknown! Shared memory comes from
// Mallocshared instead of operator new
PW-> ~ Widget (); // correct. Analyze the widgets pointed to by PW,
// But not released
// Memory containing Widgets
Freeshared (PW); // correct. Release the shared memory pointed to by PW
// But no destructor is called
As shown in the above example, if the raw memory passed to placement new is dynamically allocated by yourself (through some uncommon methods), and if you want to avoid Memory leakage, you must release it. (See comments about placement delete in my article counting objects .)
Arrays
So far, everything has been going well, but we have to continue. So far, all we have tested is to create an object at a time. How to allocate arrays? What will happen?
String * PS = new string [10]; // allocate an array
// Objects
The new operator is still the new operator, but the new operator is slightly different from a single object when an array is created. First, the memory is no longer allocated with operator new, instead of the equivalent array allocation function, which is called operator new [] (often called array new ). It can be reloaded like operator new. This allows you to control the memory allocation of arrays, just as you can control the memory allocation of a single object (but there are some restrictions, refer to Objective C ++ clause 8 ).
(Operator new [] is a relatively new thing for C ++, so your compiler may not support it. If this parameter is not supported, global operator new is used to allocate memory to each array regardless of the object type in the array. In such a compiler, it is difficult to customize the Array Memory Allocation because it needs to override the global operator new. This is not an easy task to accept. By default, all the dynamic memory allocation in the global operator new handler will have a profound and general impact on any change in its behavior. In addition, the global operator new has a normal signature (also a single parameter size_t, see Objective C ++ clause 9), So if you decide to declare it using your own method, because of these considerations, it is not a reasonable design to customize memory governance for arrays in a compiler that lacks operator new [] support .)
The second difference is the number of constructor calls by the new operator. For arrays, the constructor of each object in the array must be called:
String * PS = // call operator new [] to 10
New String [10]; // String object memory allocation,
// Call each array element
// Default constructor of the string object.
When the delete operator is used for an array, it calls the Destructor for each array element and then calls operator Delete to release the memory.
Just like you can replace or reload operator Delete, you can also replace or reload operator Delete []. There are some restrictions on their overloaded methods. Please refer to the excellent C ++ teaching materials.
The new and delete operators are built-in, and their behavior is not under your control. All the memory allocation and release functions they call can be controlled. When you want to customize the new and delete operators, remember that you cannot do this. You can only change the methods they take to complete their functions, and the functions they complete are fixed by the language and cannot be changed. (You can modify how they do what they do, but what they do is fixed by the Language)