C++: new and delete

Insert image description here

Personal homepage: Personal homepage
Personal column: "Data Structure" "C Language" "C++"


Preface

This blog serves as a knowledge summary of C++: new and detele operators


1. C++ memory management

1. Built-in types

int main()
{
    
    
	// 动态申请一个int类型的空间
	int* p1 = new int; // 未初始化
	int* p2 = new int(1); // 初始化
	// 动态申请10个连续的int类型的空间
	int* p3 = new int[10]; // 未初始化
	int* p4 = new int[10] {
    
    1, 2, 3, 4, 5}; // 初始化

	delete p1;
	delete p2;
	delete[] p3;
	delete[] p4;

	return 0;
}

Insert image description here
Insert image description here

Note: The initialization of applying for continuous space is similar to the initialization of array.
Note: To apply for and release single element space, use the new and delete operators. To apply for and release continuous space, use new[] and delete[].

2. Custom type

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		cout << "A(int a = 0)" << endl;
	}

	~A()
	{
    
    
		cout << "~A()" << endl;
	}
private:
	int _a;
};

int main()
{
    
    
	A* a = new A;
	
	delete a;
	cout << "-----------------------------" << endl;

	A* aa = new A[10];
	
	delete[] aa;
	return 0;
}

Insert image description here

Note: When applying for a custom type space, new will call the constructor and delete will call the destructor.

3. Delete and new do not match the usage problem (under VS platform)

  • Usage mismatch issues for built-in types
int main()
{
    
    
	int* p1 = new int;
	free(p1);

	int* p2 = new int[10];
	free(p2);

	int* p3 = new int;
	delete[] p3;
	return 0;
}

For built-in types, delete is equivalent to free at this time, so the program will not crash or cause memory leaks. But it is not recommended to use it like this

Insert image description here


  • Use mismatch issues for custom types
class A1
{
    
    
public:
	A1(int a = 0)
		:_a1(a)
	{
    
    
		cout << "A1(int a = 0)" << endl;
	}

	// 未写析构函数
	/*~A()
	{
		cout << "~A()" << endl;
	}*/
private:
	int _a1;
};

class A2
{
    
    
public:
	A2(int a = 0)
		:_a2(a)
	{
    
    
		cout << "A(int a = 0)" << endl;
	}

	// 写L了析构函数
	~A2()
	{
    
    
		cout << "~A()" << endl;
	}
private:
	int _a2;
};

For the above A1 category:
Insert image description here
Insert image description here
it will not cause the program to crash, but use free to release space. If this type applies for space, it will cause a memory leak.

For category A2:

Insert image description here
Insert image description here
Mismatched usage can cause the program to crash, but why? The only difference between class A1 and class A2 is that the destructor is written explicitly. This is because there is a problem with the pointer address of the space released by delete.

Insert image description here
For class A2, new is used to open up a continuous space. VS will open up an extra space before the starting address to record the number of times the destructor is called. At this time, delete p1 points to the starting address of the space, and delete[] p1 points to the space. The address of the space before the starting address.
For class A1 that does not display a destructor, the compiler will automatically generate a destructor, but the compiler will check the type of the member variables of the class. If it is a built-in type, it will not be processed. If it is a custom type, the corresponding analysis will be called. Constructor, for class A1, its member variables are built-in types, so the compiler will not open up an extra space to record the number of times the destructor is called, then delete p1 and delete[] p1 point to the same address.
Therefore, for custom types that explicitly write destructors, mismatched use will cause the program to crash.

We can do another test on category A2.
Insert image description here
Insert image description here
The program didn't crash, but the destructor was only called once.

So in general, the use of new and delete should be matched .

2. operator new and operator delete functions

new and delete are operators used by users to apply for 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 to apply for space, and delete calls the operator delete global function at the bottom to release space.

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
    
    
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)
		if (_callnewh(size) == 0)
		{
    
    
			// report no memory
			// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}

/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void* pUserData)
{
    
    
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK); /* block other threads */
	__TRY
		/* get a pointer to memory block header */
		pHead = pHdr(pUserData);
	/* verify block type */
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK); /* release other threads */
	__END_TRY_FINALLY
		return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

Through the implementation of the above two global functions, we know that operator new actually applies for space through malloc. If malloc applies for space successfully, it will return directly. Otherwise, the user-provided countermeasures for insufficient space will be executed. If the user provides this measure, it will continue to apply, otherwise Just abnormal. Operator delete finally releases space through free.

3. Implementation principles of new and delete

built-in types

If you apply for built-in type space, new and malloc, delete and free are basically similar. The difference is: new / delete applies for and releases space for one element, while new[] and delete[] apply for continuous space. Moreover, new will throw an exception when it fails to apply for space, and malloc will return NULL.

Custom type

  • The principle of new
    1. Call the operator new function to apply for space
    2. Execute the constructor on the applied space to complete the construction of the object
  • The principle of delete
    1. Execute the destructor on the space to complete the cleanup of resources in the object
    2. Call the operator delete function to release the space of the object
class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		cout << "A(int a = 0)" << endl;
	}

	~A()
	{
    
    
		cout << "~A()" << endl;
	}
private:
	int _a;
};

int main()
{
    
    
	A* a = new A;

	delete a;
	return 0;
}

Insert image description here
Insert image description here


  • The principle of new T[n]
    1. Call the operator new[] function, and actually call the operator new function in operator new[] to complete the application for n object spaces
    2. Execute the constructor N times on the applied space

  • Principle of delete[]
    1. Execute n destructors on the released object space to complete the cleanup of resources in n objects
    2. Call operator delete[] to release the space, and actually call operator delete in operator delete[] to release it space

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		cout << "A(int a = 0)" << endl;
	}

	~A()
	{
    
    
		cout << "~A()" << endl;
	}
private:
	int _a;
};

int main()
{
    
    
	A* a = new A[10];

	delete[] a;
	return 0;
}

Insert image description here

Insert image description here

Insert image description here

4. The difference between malloc/free and new/delete

  • Common points :

malloc/free and new/delete both apply for space from the heap and require the user to manually release the space

  • Differences :

Usage (malloc is cumbersome to use, new is easy to use):
malloc and free are functions, new and delete are operators.
The space applied by malloc will not be initialized. New can be initialized.
When malloc applies for space, you need to manually calculate the space size and transfer it. New only needs Just follow it with the type of space. If there are multiple objects, just specify the number of objects in []. The
return value of malloc is void*, which must be forced when used. New does not need it, because new is followed by space. When type
malloc fails to apply for space, it returns NULL, so it must be checked when using it. New does not need to, but new needs to catch exceptions.

The underlying principle (for custom types)
when applying for a custom type 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 Before releasing the space, the destructor will be called to complete the cleanup of resources in the space.


Summarize

The above is a summary of my knowledge about new and delete operators. Thanks for the support! ! !
Insert image description here

Guess you like

Origin blog.csdn.net/li209779/article/details/132977259