Some of the forms of a few forms of New (1)

xiaoxiao2021-04-09  324

A test article: Please talk about what has been Malloc function has to introduce New? A: When used in a built-in data type or structure, Malloc can meet our needs, but it is not possible when you use the class type, which requires reference to NEW, NEW to allocate the stack memory, and automatically call the class's constructor to create an object. It is this textbook to mention this, but why is these companies that are not tired? Things are not as simple as it, I am presenting these sentences. First, New and Opertor New first ask everyone a question: What is the difference between NEW and OPEARTOR NEW? If you replied: Operator New is the NEW's overloaded operator! Answer error, New is an operator in C internal definition, always like SizeOf is an operator, and Operator New is a full-class function defined by the actual definition. . Don't believe, you can write the following statement: int * p = Operator new (// This time, if the VC is used, the prototype of the function will automatically prompt. Well, there are many versions. Ok, now we get it. Clear, one is an operator, one is a global function, not the original, it is the relationship of the overload. I look at what they use? New operator is three things. Statement: myclass * p = New myclass; false code is as follows: void * Memory = Operator new (sizeof (myclass)); // 1 call global function: operator newmyclass :: myclass (); // 2 call constructor to create an object, such as The parameter // call is the reference construct function myclass * p = static_cast (memory); // 3 Convert pointer type, and assigning P we can speculate that the true memory allocation is completed in the Operator new function The .operator new function is: void * operator new (SIZE_T SIZE) THROW (std :: bad_alloc) Return Type is a void *, the parameter type is: size_t, is defined in the system header file The result of TypedEf.sizeOf () is the type of .void * operator new (size_t size) as follows: Void * p; while ((p = malloc (size)) == 0) {// memory allocation failed. IF (_callnewh (size) == 0) {_nomeMory ();}}} Return P; Whether it is successful, it is called _Nomemory () actually to throw an exception, and throws a standard library ._callnewh () function will first judge a global Whether the variable _pnhheap is zero, _pnhheap stores a function pointer, we can specify an error handler for the New operation, that is, when the new allocation of the memory fails, we call us just now. The specified function, the error handler prototype must be no array and the return type is a function of Void.

You can set our error handling function by a full-class function set_new_handler (new_handler pnew), and he is also to set our error handling function by calling _pnh _set_new_handler (_pnh pnh). The following is the definition of _PNH _SET_NEW_HANDLER (_PnH PNH): _PNH __CDECL _SET_NEW_HANDLER (_Pnh Pnh) {_Pnh Pnhold; / * Lock The Heap * / _Mlock (_HEAP_LOCK); Pnhold = _PnHeap; // Put the original error handler The pointer assigns pnhold _pnhheap = pnh; // we newly set the pointer to the function of the function. / * Unlock the heap * / _munlock (_HEAP_LOCK); return (pnhold); // Returns the pointer to the original old error handler. } Back to our _callnewh () function, if the error handler is set before myclass * p = new myclass; statement, then _pnhheap is not zero, then call (* _Pnhheap) () Our error handling function, otherwise returns zero. Then call _Nomemory () throw an exception. This error handling function is an important function. If you design, you can do a lot of things because he is a chance to be called multiple times in the While. In our error handling function, if there is no statement using exit (1) and other exit programs, there is no abnormality, and after performing our error handling function, return to while ((p = malloc (size)) = = 0), again allocate memory and judgment, or fail, call our error handling function again, of course, this error handler is different from the error handling function above, because we can call set_new_handler in the error handler above (_PNH PNH) Reset an error handler, which is the error handler of our second call. If you can't do it, you can continue to loop until you are satisfied. If you feel tired, don't play, and finally call _Nomemory () throw an exception, the function returns to the NEW call. Ok, now we know three things, first call the global operator new function, the latter allocates memory by calling the traditional Malloc function, if successful, otherwise, determine if the error handler is zero, not If zero, call our error handling function. Otherwise call _Nomemory () throws an exception. If p = malloc (size) is successful, New will then do the second thing, create an object, and finally convert the pointer type and return. We can rewrite the Operator New function. When the compiler sees statement myclass * p = new myclass; first checks our class definition to see if there is an Operator new function, if there is, call this function, then call the constructor, the transition type and return. If you do not rewrite the Operator New function, the New operator calls the Operator New function in the global, which is the function we say above. But if we are defined in front of the New operator: That's writing :: New MyClass, the compiler does not check the definition of our class and directly call the global Operator New function.

The operator NEW cannot be overloaded, just like the SizeOf operator is not overloaded. We overload is the Operator New function. So there are some qualifications, the return type of the Operator New function we overload must be a void *, the first parameter must be a size_t type. Here is a custom Operator new function: class myclass {public: myclass () {cout << "myclass :: myclass () << end1;} static void * operator new; ~ myclass () { COUT << "Myclass :: ~ myclass ()" << Endl;}}; void * myclass :: operator new (size_t size) {// You can do some of the static member data for class. We have an output statement here. COUT << "Myclass :: Operator new" << Endl; void * p = new myclass; return p;} This is not done, because in MyClass :: Operator New Void * p = New myclass's new Myclass New Yea Operator New, he did three things, the first one is to call myclass :: operator new (size_t size), so here is recursive call. Change the program to: void * myclass :: operator new (size_t size) {// You can do some control over class static member data. We have an output statement here. Cout << "Myclass :: Operator new" << Endl; void * p = operator new (size); // has been modified. Return P;} This is still not, this is direct recursive (call yourself). Just is indirect recursive. Should be changed to: void * p = :: Operator new (size); OK, use the ovelator new, or write: void * p = malloc (size), but this will not be called automatically after an error The error handler is only simply returns null, so you should pay attention to the use of the new operator to check whether the return value is zero, so it is best not to use malloc, or use :: Operator new (size) well, here you can With void * p = new char [size], use the new [] operator, and the constructor will not be called twice, nor will it be recursive. Just pay attention to releasing delete [] in the Operator delete function we rewritten. In general, we have rewritten the Operator New function, and to rewrite the Operator Delete function, and the function of the release resource in the latter is to match the function of the former. Also, you must design it to overwritten the Operator New function you want, or something to pay attention to. Fortunately, we need to rewrite this function. If you really need to rewrite, or first refer to the information in this area, There is a relevant knowledge introduction. Here I just mentioned it, let everyone know that there is such a thing, pay attention to this company's test questions.

Ocean sprinkled with thousands of words, small samples, see you dare not test this test. Second, New [] and Operator New [] New [] operator is similar to New, and do three things: call the operator new [] function, calendar all the Vector call constructor. Conversion points to the pointer type of the first address and returns. The Operator New [] function calculates the A and Number in the operator new a [number]: size_t count = number * sizeof (a), then call the global function operator new (count). Three new (void *) Myclass Operator new (size_t, void *) specified location creation operator new () is also three things, the first one is to call the Operator New (size_t, void *) function, the last two of the following two and new operators are the same. Let's take a look at the definition of operator new (size_t, void *) in vs.net: inline void * __ cdecl operator new (size_t, void * _where) _throw0 () {// construct array with placement at _where return (_where); } And Operator New Compared to simple, we have seen it, he did not call the malloc function, nor did the Operator new function, how did he assign the memory? For the operator new function, he assigns a memory by looping the malloc function, it is best to return this allocated memory Return P to the operator New, let him do the second and third things above. We return here (_where); press this reason, _where6 should point to an allocated memory. _Where came from there? The answer is specified using the operator new (void * _where) MyClass. This is the usage of the specified location to create operator new (), first assign a piece of memory, then call new (), new (), will create an object at this specified location , Then put the first address of this specified memory home to P, then convert the type and return. Such a subunit NEW () does not really allocate memory, so it cannot call Delete to release memory. When the degree is created using shared memory or Memory-mapped I / O, it is more useful because the object must be placed in a determined address or a memory allocated by the routine. Let's look at an example. #include #include // To create an operator using the specified location to publish the header file. Using namespace std; void * mallocshared (size_t size); // is used to assign shared memory, which is written by other programmers. You only know that you can get a distributed and unin-initialized memory by //.

Class a {public: a () {cout << "A:: A ()" << endl; m_n = 0;} int GET () {return m_n;} ~ a () {cout << "A :: ~ A () "<< endl;} private: int m_n;}; int main () {void * p = mallocshared (sizeof (a)); // This sentence is also possible to call other places, // Then pass the P. Here is to simplify the A * PA = New (P) a; cout << pa-> get () << end1; delete pa; return 0;} / * The following is another programmer in a module Written mallocshared () function, you don't know its specific implementation, just by exporting the function. * / void * mallocshared (size_t size) {void * p = malloc (size); if (p == null) {cerr << "mallocshared (size_t size) failed!" << Endl; exit (1);} return P;} Is this program problem? I don't say good or bad, whether the program can be compiled? If possible, how is the result of the operation? Please think about three minutes. If you have any questions, it may be this DELETE PA; function mallocshared is not you wrote, you don't know what to allocate in any way, call DELETE to release it? If we let us know that he is allocated by the malloc function, can you release it with DELETE? The answer is: can be compiled, and can get the correct result, the memory used by the Malloc function is not problematic, the New operator is not allocated by Malloc, and you can also use Delete to release. If mallocshared is the following, what is the situation? Void * mallocshared (new char [size]);} The result is the same as above, the delete p is fine, just use new [] to allocate the size of the memory block and the memory released with Delete There is no problem like size. Recall that, when we use new a to allocate memory, it is actually assigned by Operator New (Size). Size = SizeOf (a) here, in this case we can use Delete P to release, as long as P The type is A *, because DELETE is released by calling the operator delete (size) function, the size is also equal to SIZEOF (P), when we call new char [numBer], first call the operator new [] function, then In fact, it is also called the memory of Operator New (Number * Sizeof (Char)), since the memory allocated by calling the Operator New, call Delete to release should also be no problem.

Because here: mallocshared (SizeOf (a)) ----> size == sizeof (a) == size * sizeof (char) == sizeof (p) size is the same. Changed to: void * mallocshared (size_t size);} The result is the same! Of course, if you do not provide your own Operator New function, if you rewrite the Operator new function Change to: void * mallocshared (size_t size) {return (:: operator new (size)); // Using global functions} This program is no problem, but there are many security hazards, it is easy to make mistakes, no Be careful in the ditch, there is a "undefined" behavior, and the result is possible to happen. You should be invited to write such a procedure. The above is said to mallocshared (SizeOf (a)); may not be called in your program, but in someone call, then others send you a pointer to call this pointer as a parameter to call your own A * PA = New (p) a, you call Delete P to release, others still need to use, because this is a shared memory, or after the work you want to do, call Delete, this The child has a problem. The same memory cannot be released twice. Even if Mallocshared (SizeOf (a)) is called here, then you can be a memory distributor, you have the right and your obligation to release him, but you must first determine that others need to use this memory. If you need it, you can't go right away, or you will still need it yourself, and you will be created in this memory. So you don't have to call Mallocshared (SIZEOF (a)); to allocate memory. Change the main function to the following, what is the result, can it be compiled? INT main () {void * p = mallocshared (SIZEOF (A)); // The limited is called here. A * pa = new (p) a; cout << pa-> get () << endl; a * pa1 = new (p) a; // again specify location creation. Delete Pa; RETURN 0;} The answer is: can be compiled, the results are as follows: A :: A () 0A :: A () ~ a :: a () The original memory is indeed released, Just here constructor A:: A () call twice, the destructor A :: ~ a () is only called once, which is obviously not very good, if your class has allocated resources elsewhere, it needs to be destructured The function is released, so you should use a destructor that will cause memory leaks or other problems. Therefore, the program should be changed to the following: int Main () {void * p = mallocshared (SIZEOF (A)); // Limited is called here. A * pa = new (p) a; cout << pa-> get () << endl; a * pa1 = new (p) a; // again specify location creation. PA-> ~ a (); // Explicitly call the destructor to sect the object, but the memory is not released, and it can be used again.

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

New Post(0)