Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

The usage of new and delete in C++

2025-01-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article introduces the relevant knowledge of "the usage of new and delete of C++". Many people will encounter this dilemma in the operation of practical cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Internal implementation of new and delete

In C++, you need to use the keywords new and delete to create and destroy objects in heap memory. For example, the following code

Class CA {public: CA () CA (0) {} CA (int a): Massia (a) {} virtual void foo () {coutm_a = 20 delete p1-> ~ CA (); p2-> CA (); delete [] buf2

You can see that buf1 is stack memory and buf2 is heap memory in the code, both of these memory areas are allocated memory, and now we want to use these memory as objects of the CA class, so we need to call the class constructor CA::CA () to the memory. The internal implementation of the constructor will fill the memory area with virtual table pointers, so that objects can call virtual functions such as foo. But it's not elegant to write code like this, so is there a more elegant way to build objects on an existing piece of memory? The answer is placement technology. In C++, new and delete are still used to implement this technology. In addition to implementing the default operators, new and delete overload the following operator functions:

Void* operator new (size_t size, void* p) {return p;} void* operator new [] (size_t size, void* p) {return p;} void operator delete (void* p1, void* p2) {/ / do nothing..} void operator delete [] (void* p1, void* p2) {/ / do nothing..}

We call these four operators placement new and placement delete. Through these operators, we can achieve the above functions gracefully:

Char buf1 [100]; CA * p1 = new (buf1) CA (10); / / call operator new (size_t, void*) p1-> foo (); char * buf2 = new charchar[ sizeof (CA)]; CA * p2 = new (buf2) CA (20); / / call operator new (size_t, void*) p2-> foo (); p1-> CA (); operator delete (p1, buf1); / / call operator delete (void*, void*) p2-> CA (); operator delete (p2, buf2) / / call operator delete (void*, void*) delete [] buf2

In the above example, it is found that objects can be elegantly built in existing memory through placement new, but destructors and placement delete functions must be called artificially instead of directly calling delete p1 and delete p2 to destroy objects. And from the above placement delete implementation, there is no code in it, so why define a placement delete? The answer is that C++ stipulates that operator overloading of new and delete must be implemented in pairs. And as mentioned earlier, the use of delete with the operator prefix is just a normal function call. Therefore, in order to complete the destructor and match with the new operator, it is necessary to artificially call the object's destructor and the placement delete function.

In addition to the above examples, the use of placement technology can also reduce frequent memory allocation and improve system performance.

Void main () {for (int I = 0; I)

< 10000; i++) { CA *p = new CA(i); p->

Foo (); delete p;}}

There are 10000 loops in the example, each of which creates a heap memory object, and then calls the virtual function foo before destroying it. The end result is frequent heap memory allocation and destruction 10000 times when the program is running. It is obvious that this may affect system performance and heap memory allocation failures may also occur. And if we use placement technology, we can easily solve these problems.

Void main () {char * buf = new [] (sizeof (CA)); for (int I = 0; I

< 10000; i++) { CA *p = new(buf) CA(i); p->

Foo (); p-> ~ CA (); operator delete (p, buf);} delete [] buf;}

In the above example, there is only one heap memory allocation, and in the loop, objects are built with existing memory, and memory is no longer allocated. In this way, the reuse of memory makes the performance of the program greatly improved.

New and delete operator overloading

It is interesting to find that the more advanced the language is, the more likely it is to encapsulate some of the things at the bottom of the system and form a language-level keyword to use. For example, new and delete in C++ are keywords used to build and release heap memory objects, and the chan keyword in go language is used for synchronous or asynchronous queue data transfer channel.

C++ language implements a set of global new and delete operator functions as well as placement new/delete operator functions by default. Both classes and built-in types can allocate and release heap memory objects through new/delete. For a class, when we use new to build an object, we first check to see if the class overloads the new operator, and if the class overloads the new operator, it invokes the new operator provided by the class for memory allocation, and if no new operator is provided, the global new operator provided by the system is used for memory allocation. Built-in types always allocate memory using the global new operator provided by the system. The memory destruction process of the object is also consistent with the allocation.

The new and delete operators support both global overloading and class-level function overloading. The following is the format of the definition of this operator:

/ / Global operator definition format void * operator new (size_t size [, param1, param2,....]); void operator delete (void * p [, param1, param2,...]); / / in-class operator definition format class CA {void * operator new (size_t size [, param1, param2,....]); void operator delete (void * p [, param1, param2,...]);}

There are always rules for new/delete operator overloading:

New and delete operator overloads must occur in pairs

The first parameter of the new operator must be of type size_t, which specifies the size size of the allocated memory; the first parameter of the delete operator must be the memory object to be destroyed. Other parameters can be defined at will.

The system implements six operator functions: new/delete, new [] / delete [] and placement new/delete by default. They all have a specific meaning.

You can override the default implementation of the global operator, such as you want to customize the memory allocation policy, or you want to monitor the allocation of heap memory or you want to do memory leak monitoring for heap memory. But the global operator you rewrite must meet the default rule definition.

If you want to do special handling on objects allocated to the heap memory of a class, you can overload the class's new/delete operator. Although there is no static attribute when these two operators are overloaded, overloading the class's new/delete operator is always considered a static member function anyway.

When the parameters of the delete operator are > = 2, you are responsible for calling the object destructor and calling the delete operator as an operator function.

In general, you don't need to overload the new/delete operator, unless your entire application or a class has special requirements. In the following example, you can see the overloading and use of my various operators:

/ / CA.hclass CA {public: / / Class member function void * operator new (size_t size); void * operator new [] (size_t size); void * operator new (size_t size, void * p); void * operator new (size_t size, int a, int b); void operator delete (void * p); void operator delete [] (void * p); void operator delete (void * p, void * p1); void operator delete (void * p, int a, int b);} Class CB {public: CB () {}}; / / Global operator function, be careful to override the global operator function. Void * operator new (size_t size); void * operator new [] (size_t size); void * operator new (size_t size, void * p) noexcept;void * operator new (size_t size, int a, int b); void operator delete (void * p); void operator delete [] (void * p); void operator delete (void * p, void * p1); void operator delete (void * p, int a, int b) . / / CA.cppvoid * CA::operator new (size_t size) {return malloc (size);} void * CA::operator new [] (size_t size) {return malloc (size);} void * CA::operator new (size_t size, void * p) {return p } void* CA::operator new (size_t size, int a, int b) {return malloc (size);} void CA::operator delete (void* p) {free (p);} void CA::operator delete [] (void* p) {free (p);} void CA::operator delete (void* p, void* p1) {} void CA::operator delete (void* p, int a, int b) {free (p);} void* operator new (size_t size) {return malloc (size) } void* operator new [] (size_t size) {return malloc (size);} void* operator new (size_t size, void* p) noexcept {return p;} void* operator new (size_t size, int a, int b) {return malloc (size);} void operator delete (void* p) {free (p);} void operator delete [] (void* p) {free (p);} void operator delete (void* p, void* p1) {} void operator delete (void* p, int a, int b) {free (p) }.. / / main.cppint main (int argc, const char * argv []) {char buf [100]; CA * A1 = new CA (); / / call void * CA::operator new (size_t size) CA * a2 = new CA [10]; / / call void * CA::operator new [] (size_t size) CA * a3 = new (buf) CA () / / call void* CA::operator new (size_t size, void* p) CA * a4 = new (10,20) CA (); / / call void* CA::operator new (size_t size, int a, int b) delete A1; / / call void CA::operator delete (void* p) delete [] a2 / / calling void CA::operator delete [] (void * p) / / A3 is allocated in the way of placement new, so you need to call the object's destructor yourself. A3-> ~ CA (); CA::operator delete (A3, buf); / / call void CA::operator delete (void * p, void * p1), remember to bring the class namespace. / / a4 has operator parameters greater than or equal to 2, so you need to call the object's destructor yourself. A4-> ~ CA (); CA::operator delete (a4, 10, 20); / / call the void CA::operator delete (void * p, int a, int b) / / CB class does not have an overloaded operator, so a globally overloaded operator is used. CB * b1 = new CB (); / call void * operator new (size_t size) CB * b2 = new CB [10]; / / call void * operator new [] (size_t size) / / you can see here that the same block of memory can be used to build objects of CA classes as well as objects of CB classes CB * b3 = new (buf) CB () / call void* operator new (size_t size, void* p) CB * b4 = new (10,20) CB (); / call void* operator new (size_t size, int a, int b) delete b1; / / call void operator delete (void* p) delete [] b2; / / call void operator delete [] (void* p) / / b3, so you need to call the object's destructor. B3-> ~ CB ();:: operator delete (b3, buf); / / call void operator delete (void * p, void * p1) / / b4 operator parameters are greater than or equal to 2, so you need to call the object's destructor. B4-> ~ CB ();:: operator delete (b4,10,20); / / call void operator delete (void * p, int a, int b) return 0;}

I tested the above code on XCODE because the global new/delete operator was rewritten and heap memory allocation was internally achieved through malloc, and the malloc function stated that the return result check that NULL could not be returned:

Void * malloc (size_t _ _ size) _ _ result_use_check _ alloc_size (1)

So it's possible that you will crash during the test. If this problem occurs, you can try to comment out the code rewritten to the global new/delete, and then run to see the results. It can be seen that there may be risks if you try to overwrite the global new/delete.

Automatic deletion technology of object

Generally speaking, the default implementation of new/delete in the system can meet our needs, and we no longer need to overload these two operators. So why does C++ provide overloading support for these two operators? The answer lies in the flaws in the operator itself. We know that using the new keyword to create a heap memory object is divided into two steps: 1. Is heap memory allocation, 2. Is a call to the object constructor. Either of these two steps can lead to an exception. If there is a problem in the first step and the memory allocation fails, the constructor will not be called, which is no problem. If it is said that an exception occurred during the execution of the second-step constructor and the normal construction cannot be completed, then the heap memory allocated in the first step should be destroyed. C++ states that if an object cannot be fully constructed, then the object will be an invalid object and the destructor will not be called. In order to ensure the integrity of the object, when the heap memory object allocated through new has an exception during the execution of the constructor, it will stop the execution of the constructor and automatically call the corresponding delete operator to destroy the allocated heap memory. This is the so-called automatic deletion technology of objects. It is precisely because of the automatic deletion technology of objects that the problem of memory leakage caused by incomplete object construction can be solved.

When an exception is thrown during object construction, C++ 's exception handling mechanism inserts code in a specific place to call the object's delete operator. If you want to know more about the situation, please refer to C++ 's relevant knowledge about exception handling.

Although the automatic deletion of objects supported by the global delete operator function can solve the problem of memory leakage of the object itself, it cannot solve the problem of memory allocation leakage of data members within the object constructor. Let's take a look at the following code:

Class CA {public: CA () {m_pa = new int; throw 1;} ~ CA () {delete masked paws; m_pa = NULL;} private: int * mumbaa;}; void main () {try {CA * p = new CA (); delete p; / / this code will never execute} catch (int) {cout masked pas; free (p);} private: int * mshelpas;}

Because of C++ 's support for automatic deletion, when an exception occurs in the CA object during construction, we can overload the delete operator to solve the memory problem of the data members allocated in the constructor without calling the destructor to destroy it. I think that's why overloading new/delete operators in classes is supported in C++.

Let's take a look at the following: considerations for using new and delete

1. New and delete are both built-in operators, and the language itself is fixed and cannot be re-customized. it is futile to customize the behavior of new and delete.

two。 If dynamic allocation fails, a null pointer (NULL) is returned, indicating that an exception occurred, insufficient heap resources and allocation failure.

3. Pointer deletion and heap space release. Deleting a pointer p (delete p;) actually means deleting the target that p refers to (variables or objects, etc.), freeing up the heap space it occupies, rather than deleting p itself (pointer p itself is not undone, it still exists, and the memory space occupied by the pointer is not freed). After releasing heap space, p becomes a null pointer.

4. Memory leaks (memory leak) and repeated releases. New is paired with delete, and delete can only free up heap space. If the pointer value returned by new is lost, the allocated heap space cannot be reclaimed, which is called a memory leak, and it is also dangerous to release the same space repeatedly, because the space may have been allocated separately, so the pointer returned by new must be properly saved to ensure that memory leaks do not occur and that heap memory space is not repeatedly freed.

5. The lifetime of a dynamically assigned variable or object. We also call heap space free space (free store), but we must remember to release the heap space occupied by the object only once, to build it within the function, and to release it outside the function, which is often an error.

6. Access to the structure space opened up by new cannot be done directly through the variable name, but only through the pointer to the assignment.

Address space can be opened and revoked dynamically with new and delete. When programming, if you run out of a variable (usually temporarily stored data) and need to use it again next time, but you want to save the effort of reinitialization, you can open up a space each time you start using it and undo it after use.

This is the end of the introduction of "the usage of new and delete of C++". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report