C/C++ memory management (new&delete detailed explanation)

introduction

In the previous part of C language, we have introduced the division of storage areas in memory: including kernel space (user code cannot access), stack, memory mapping segment (file mapping, dynamic library, anonymous mapping), heap, data segment ( static area), code segment (constant area) .
And you can skillfully use malloc, calloc, realloc, and free for dynamic memory management:
C language dynamic memory management details

But in C++, when using these functions for dynamic memory management, some requirements cannot be met (such as initializing objects when applying for space), and it is more troublesome to use. So C++ proposes a way to dynamically apply for newspace delete:

The use of new and delete

Unlike malloc and free, new and delete are operators rather than functions .

When using new and delete to apply for space:
For a single element, use new 类型;to apply for a space of a specified type, and the value of the expression is a pointer to this space. You can use parentheses after the type to initialize the value of this type new 类型(初始值);;
correspondingly, you need to use delete 指针;the form to release the space of this single element.

For continuous elements, use new 类型[num];to apply for a continuous space of num types, and the value of the expression is the address of this space. You can use {} after [num] to initialize this space: new 类型[num]{};;
Correspondingly, you need to use delete[] 指针;the form to release the space of this continuous element.

built-in type

According to the rules introduced above, the following codes are available for the dynamic application space of the built-in type:

int main()
{
    
    

	int* p1 = new int;  
	//动态开辟一块int的空间,不初始化
	int* p2 = new int(10);  
	//动态开辟一块int的空间,初始化为10
	int* p3 = new int[10];  
	//动态开辟一块10个int的空间,不初始化
	int* p4 = new int[10]{
    
     1,2,3,4,5,6,7,8,9,0 }; 
	//动态开辟一块i10个int的空间,初始化为1,2,3,4,5,6,7,8,9,0

	delete p1;
	delete p2;
	//释放单个元素空间用delete
	delete[] p3;
	delete[] p4;
	//释放连续空间需使用delete[]

	return 0;
}

We can view the values ​​in the space applied for by each part by debugging:

insert image description here
insert image description here
insert image description here
insert image description here
It should be noted that newand delete, new []and delete[]cannot be mixed. Although there will be no problems when dynamically applying for built-in types, the program will crash for custom types.

custom type

For built-in types, using malloc and free can barely meet our needs, but for custom types, such as class types, we need to initialize class objects when applying for space, and malloc obviously cannot meet our needs.

After new dynamically applies for space, it will also call the default constructor; delete will release the dynamically applied space after calling the destructor.
Here you need to pay special attention to the difference between the space of class objects and the resource space in class objects :

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		_date = new char[_a + 1] {
    
    0};
		cout << "A(int a = 0)" << endl; //构造函数中打印
	}
	~A()
	{
    
    
		delete[] _date;
		_a = 0;
		cout << "~A()" << endl;  //析构函数中打印
	}
private:
	int _a;
	char* _date;
};

For example, this class A has two member variables intand char*occupies 8 bytes. These 8 bytes are the space of the class object. This space can be in the stack area or dynamically applied in the heap area, depending on the user;
but It char*points to a continuous space. The size of this space is uncertain. It is dynamically applied in the constructor when the class object is instantiated, which cannot be changed by the user of the class. This dynamically opened space is the resource of the class, which can only be applied in the constructor and released in the destructor. This is why malloc cannot satisfy our dynamic application space for custom types.

insert image description here

For the new custom type, the usage is consistent with the built-in type:
when using new to apply for a single object, the constructor is called once, when applying for num consecutive objects, the constructor is called num times; delete is the same:

int main()
{
    
    
	A* pa1 = new A;
	//动态开辟一个对象,调用默认构造初始化
	A* pa2 = new A(5);
	//动态开辟一个对象,传参给构造函数初始化
	A* pa3 = new A[5];
	//动态开辟一块连续的类对象空间,全部调用默认构造初始化
	A* pa4 = new A[5]{
    
     1,2,3,4,5 };
	//动态开辟一块连续的类对象空间,分别传参初始化

	delete pa1;
	delete pa2;
	//释放单个元素空间用delete
	delete[] pa3;
	delete[] pa4;
	//释放连续空间需使用delete[] !!!

	return 0;
}

We can check the status of the dynamic application by debugging:
insert image description here
insert image description here
insert image description here
insert image description here
a total of 1+1+5+5=12 constructors and 12 destructors are called:
insert image description here

The realization principle of new and delete

built-in type

If you are applying for a built-in type of space, new and malloc, delete and free are basically similar. However new, deletethe application and release are for the space of a single element, new []and delete[]the application is for continuous space, and newwhen the application space fails, an exception will be thrown and mallocNULL will be returned

It should be noted that when dynamically applying or releasing space, C++ is more inclined to throw an exception to reflect the cause of the failure when the application or release fails. This behavior of throwing an exception is implemented in two functions operator new. We can also check through disassembly that when a new space is created, the operator new function is indeed called, and when the delete is done, the operator delete function is indeed called: Of course, when applying and releasing continuous space, the and function is called. However, these two functions are implemented by calling multiple and .operator delete

insert image description here
insert image description here
operator new[]operator delete[]operator newoperator delete

Understanding operator new and operator delete functions

We can take a brief look at the operator newAND operator deletefunction:

new and delete are operators for users to apply and release dynamic memory. operator new and operator delete are global functions provided by the system. new calls the operator new global function at the bottom layer to apply for space, and delete uses the operator delete global function at the bottom layer to release space .

In fact, the application space operator newis also passedmalloc . If the malloc application space is successful, it will return directly. Otherwise, the countermeasures provided by the user for insufficient space will be implemented. If the user provides this measure, the application will continue, otherwise an exception will be thrown. operator deleteUltimately it is through freeto free up space .

custom type

  1. The principle of new
    Call operator newthe function to apply for space, and then execute the constructor on the applied space to complete the construction of the object.

  2. The principle of delete
    Executes the destructor on the space, completes the cleanup of resources in the object, and then calls operator deletethe function to release the space of the object

  3. The principle of new T[num]
    calls operator new[]the function, actually calls the function in operator new[] operator newto complete the application of num object spaces, and executes the constructor num times on the applied space

  4. The principle of delete[]
    Execute num destructors on the released object space, complete the cleaning of resources in num objects, and then call the operator delete[]release space, which is actually called in operator delete[] operator deleteto release the space

positioning new

Locating new can use a piece of dynamic space that has been applied to call the constructor to initialize the class object

Locating new is usually used in conjunction with the memory pool (the memory pool is a space that has been applied for in advance. Applying for a part of the space in advance can avoid the reduction in efficiency caused by frequent application space due to frequent expansion). The space in the memory pool is only for application, not Initialization, we can achieve initialization by locating new:

The format of using positioning new is: new (要初始化的空间的指针) 类型;, it should be noted that if the class type to be initialized does not have a default constructor, parameters must be passed; new (要初始化的空间的指针) 类型(构造函数参数列表);when
releasing the resources of the class object initialized by positioning new, it is necessary to explicitly call the class object The destructor to deallocate:

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		_date = new char[_a + 1] {
    
    0};
		cout << "A(int a = 0)" << endl; //构造函数中打印
	}
	~A()
	{
    
    
		delete[] _date;
		_a = 0;
		cout << "~A()" << endl;  //析构函数中打印
	}
private:
	int _a;
	char* _date;
};

int main()
{
    
    
	A* ptr = (A*)malloc(1000);
	//创建1000个字节的空间
	new(ptr)A(5);
	//用上面申请的空间初始化一个A对象
	ptr->~A();
	//释放上面定位new初始化的对象的资源
	free(ptr);
	//释放malloc出的空间
	return 0;
}

The point to note is the difference between class space and class resource space : here malloc just applies for a piece of space, and the following new is to initialize the space in malloc. This initialization behavior includes applying for class resources, which do not belong to malloc out of the space;
delete releases the resources of the class, and free loses the space out of malloc.

The difference between new&delete and malloc&free

  1. malloc and free are functions; new and delete are operators

  2. The space requested by malloc will not be initialized; new can be initialized

  3. When malloc applies for space, you need to manually calculate the size of the space and pass it on; new only needs to be followed by the type of space. If there are multiple objects, specify the number of objects in [num]

  4. The return value of malloc void*must be forced when used; new does not need it, because the type of space will be specified after new

  5. When malloc fails to apply for space, it returns NULL, so it must be judged as empty when using it; new does not need it, but new needs to catch exceptions

  6. When applying for a custom type of object, malloc/free will only open up space, and will not call the constructor and destructor; while new will call the constructor to complete the initialization of the object after applying for space, and delete will call the destructor before releasing the space Complete the cleanup of resources in the space

Summarize

At this point, the introduction of C/C++ memory management is over.
I believe that you have not only learned the use of new and delete in C++, but also deepened your understanding of memory management.

If you think that I did not introduce a certain part clearly or that there is a problem with a certain part, you are welcome to raise it in the comment area

If this article is helpful to you, I hope it will be connected with one click

Hope to make progress together with you

Guess you like

Origin blog.csdn.net/weixin_73450183/article/details/131139176