Article directory
- 1. C/C++ memory distribution
- 2. Dynamic memory management method in C language: malloc/calloc/realloc/free
- 3. C++ memory management method
-
- 1. New/delete operation built-in types
- 2. New / delete operation custom type
- 4. operator new and operator delete functions
- 5. Implementation principles of new and delete
-
- 1. Built-in types
- 2. Custom type
- 6. Positioning new expression (placement-new)
- 7. The difference between malloc/free and new/delete
1. C/C++ memory distribution
Let’s look at a piece of code and related memory distribution issues
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string.h> int globalVar = 1; static int staticGlobalVar = 1; voidTest() {<!-- --> static int staticVar = 1; int localVar = 1; int num1[10] = {<!-- --> 1, 2, 3, 4 }; char char2[] = "abcd"; char* pChar3 = "abcd"; int* ptr1 = (int*)malloc(sizeof (int)* 4); int* ptr2 = (int*)calloc(4, sizeof(int)); int* ptr3 = (int*)realloc(ptr2, sizeof(int)* 4); free(ptr1); free(ptr3); std::cout << "sizeof(num1):" <<sizeof(num1) << std::endl; std::cout << "sizeof(char2):"<<sizeof(char2) << std::endl; std::cout << "strlen(char2):" << strlen(char2) << std::endl; std::cout << "sizeof(pChar3):" << sizeof(pChar3) << std::endl; std::cout << "strlen(pChar4):" << strlen(pChar3) << std::endl; std::cout << "sizeof(ptr1):" << sizeof(ptr1) << std::endl; } int main() {<!-- --> Test(); return 0; }
globaVar
is a global variable, accessible to all files, stored in the data segment.staticGlobalVar
is a static global variable that can only be accessed by the current file and is stored in the data segment.staticVar
is a static local variable that can only be accessed by the current function and is stored in the data segment.localVar
is a local variable, stored on the stack.num1
is a local variable, stored on the stack.
char2
is the name of the array. The string"abcd"
is stored in the constant area. When creating the array, a copy of"abcd\0"
In the stack space, the address of the first element'a'
is the address of the array name.In the stack space.*char2
is a dereference to the address of the first element of the array,*char2
is equivalent to the first element of the arraya
, in the stack space strong>.pChar3
is a pointer variable, pointing to the constant string"abcd"
stored in the data area,const
is limited to*pChar3
, stored on stack.*pChar3
is a dereference topChar3
, which is actuallya
in the data area, in the data sectionptr1
points to the first address of the space returned bymalloc
, butptr1
itself is temporarily created by themain
function , stored in stack space*ptr1
is the first four-byte space data in the dynamically allocated space, stored in the heap space
2. Dynamic memory management method in C language: malloc/calloc/realloc/free
void Test() {<!-- --> int* p1 = (int*)malloc(sizeof(int)); free(p1); int* p2 = (int*)calloc(4, sizeof(int)); int* p3 = (int*)realloc(p2, sizeof(int) * 10); //free(p2); // Is free(p2) needed here? free(p3); }
Here p2
does not need to be released manually. realloc
If the space application is successful, the original space will be released automatically. font>
- The only difference between
malloc
andcalloc
is thatcalloc
will initialize the allocated space to 0, whilemalloc
will not The applied space is initialized. realloc
: If the original address can store the newly opened space, the original address will be expanded directly; if the original address does not have such a large space, a new space will be found and the original space will be automatically released. Returns the starting address of the new space.
3. C++ memory management method
The C language memory management method can continue to be used in C++, but it is ineffective in some places and is more troublesome to use. Therefore, C++ has proposed its own memory management method: via
new
anddelete
operator for dynamic memory management.
1. New / delete operation built-in types
void Test() {<!-- --> // Dynamically apply for a space of type int, which will not be initialized. int* ptr1 = new int; // Dynamically apply for a space of type int and initialize it to 10 int* ptr2 = new int(10); // Dynamically apply for ten int type spaces and will not initialize them. int* ptr3 = new int[10]; // Dynamically apply for ten int type spaces and initialize them according to the list int* ptr4 = new int[10]{<!-- -->1, 2, 3}; //The fourth element is initialized to 0 by default delete(ptr1); delete(ptr2); delete[](ptr3); delete[](ptr4); }
Note:
To allocate and release space for individual elements, use the new
and delete
operators.
To allocate and release contiguous space, use the new[]
and delete[]
operators.
There is no difference in usage between new
and malloc
. The difference is that new
can initialize that space at the same time when applying for space< /strong>, and malloc
can only apply for space.
2. New / delete operation custom type
class A {<!-- --> public: A(int a) :_a(a) {<!-- --> cout << "A(int a): " <<this << endl; } ~A() {<!-- --> cout << "~A(): " <<this << endl; } private: int _a; }; int main() {<!-- --> //The biggest difference between new/delete and malloc/free is that new/delete will also call the constructor and destructor to open and release space for custom types. A *ptr1 = (A*)malloc(sizeof(A)); A *ptr2 = new A(1); free(ptr1); delete(ptr2); return 0; }
The result is as follows:
new
and delete
will call the constructor and destructor of the custom type.
But malloc
and free
will not, they will only apply for space and release space.
new
is a continuous space. If there are several elements, the constructor and destructor will be called several times. At the same time, the order of construction first and then destruction will be followed.
// new[] / delete[] A* ptr3 = new A[3]{<!-- -->1, 2, 3}; // C++11 uses list initialization delete[](ptr3);
Here is a more complex stack custom type
class Stack {<!-- --> public: Stack(int capacity = 4) :_capacity(capacity) ,_top(0) {<!-- --> cout << "Stack(int capacity = 4)" << endl; _array = new int[_capacity]; } ~Stack() {<!-- --> cout << "~Stack()" << endl; delete[](_array); _array = nullptr; _capacity = _top = 0; } private: int* _array; int _capacity; int _top; }; int main() {<!-- --> Stack* p1 = new Stack(5); delete(p1); return 0; }
For custom types, the difference between new/delete
and malloc/free
is that new/delete
will call the constructor and destructor respectively.
Here, there is definitely a problem with free(p1)
. free
will not call the destructor of the custom type before releasing the custom type object space. Then The space pointed to by _array
has not been released, causing a memory leak.
For the new
operation, what should be done if new
fails?
In C++, exceptions are handled by catching exceptions, which will be explained in detail later. Here we briefly show the following usage.
void Test() {<!-- --> char* p1 = new char[1024*1024*1024]; cout << (void*)p1 << endl; // The char* type cannot use cout directly and will be automatically recognized as a string. char* p2 = new char[1024*1024*1024]; cout << (void*)p2 << endl; } int main() {<!-- --> try {<!-- --> Test(); } catch(const std::exception & amp; e) {<!-- --> cout << "1" << endl; std::cerr << e.what() << '\ '; } return 0; }
If the space creation fails for the second time, the exception will be caught directly and printed out, and the program will not crash.
4. operator new and operator delete functions
new
anddelete
are operators for dynamic memory application and release,operator new
andoperator delete
are global functions provided by the system.
new
At the bottom level, apply for space by callingoperator new
global function.delete
At the bottom level, call < /strong>operator delete
global function to free up space.
The operator new
and operator delete
functions are library global functions, which are encapsulations of malloc
and free
and do not call the constructor. and destructor.
If the application for space fails, an exception will be thrown directly, and the original malloc
can only return 0.
/* operator new: This function actually applies for space through malloc, and returns directly when malloc successfully applies for space; apply for space If it fails, try to implement insufficient space countermeasures. If the countermeasures are set by the user, continue to apply, otherwise an exception will be thrown. */ 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 // If the memory application fails, a bad_alloc type exception will be thrown here. static const std::bad_alloc nomem; _RAISE(nomem); } return(p); } /* operator delete: This function finally releases space through 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; } /* implementation of free */ #define free(p) _free_dbg(p, _NORMAL_BLOCK)
The following three operations for dynamically allocating memory space for built-in types are the same.
int main() {<!-- --> int* p1 = (int*)malloc(sizeof(int)); free(p1); int* p2 = new int; delete(p2); int* p3 = (int*)operator new(sizeof(int)); operator delete(p3); return 0; }
Then the following code can also know how the underlying layer is called.
Stact* p1 = new Stack[10]; delete[](p1);
First, operator new
is called to open up a space of 160
bytes. Then the constructor is called 10 times, creating 10 custom objects of the Stack
class. Define type object.
However, through debugging, I found that it was not 160
bytes that were opened, but 168
bytes. The parameter sz of
is operator new
was passed in. 168
After the space is allocated, the value of p1
is 0x614c28
. By observing 0x614c20
, it is found that 8
more bytes have been allocated. Space, which stores the number of array elements 10
Replace the code, Stack* p1 = new Stack[8];
Found that the address pointed to by p1
is indeed 8
forward by 8
This number exists because the custom type has a destructor and you need to know how many times the destructor needs to be called.
At this time, if I mistakenly use delete
instead of delete[]
, it will directly cause the program to crash. The program actually starts applying at 0x614c20
168
bytes of space. Using delete[]
will automatically pass the address into operator delete
, and delete
will not be processed in this way, and the original 0x614c28
will be passed into the function. This address is not the first address of the applied space, and the release fails.
But if it is a built-in type, it may not crash
int* p2 = new int[10]; delete(p2);
Built-in types do not have destructors, so there is no need to open an extra space to record how many times the destructor needs to be called. In this way, the program will not crash.
Through the above debugging, you can get the following programming notes.
new/delete
,new[]/delete[]
,malloc/free
must be used together, otherwise the result will be undetermined.
5. Implementation principles of new and delete
1. Built-in types
If you are applying for a built-in type of space,
new
andmalloc
,delete
andfree
are basically similar, with some differences. yes:
new/delete
applies for and releases the space of a single element, whilenew[]/delete[]
applies for and releases continuous space.
new
will throw an exception when the application fails, andmalloc
will returnNULL
2. Custom type
-
The principle of
new
- Call the
operator new
function to construct the space - Execute the constructor on the requested space to complete the construction of the object
- Call the
-
The principle of
delete
- Execute the destructor on the space to complete the cleanup of resources in the object
- Call the
operator delete
function to release the space of the object
-
The principle of
new[]
- Call the
operator new[]
function, and actually call theoperator new
function inoperator new[]
to complete the application for N object spaces. - Execute the constructor N times on the allocated space
- Call the
-
The principle of
delete[]
- Execute N destructors on the released object space to complete the cleanup of resources in N objects
- Call
operator delete[]
to release space. Actually calloperator delete
inoperator delete[]
to release space.
6. Positioning new expression (placement-new)
Positioning the new
expression is to call the constructor to initialize an object in the allocated original memory space
Usage format:
new(place_address)type or new(place_address)type(initializer-list) place_address must be a pointer and initializer-list is the type's initializer list.
scenes to be used:
The positioning new
expression is generally used with the memory pool in practice. Because the memory allocated by the memory pool is not initialized, if it is a custom type object, you need to use new
The definition expression explicitly calls the constructor for initialization.
class A {<!-- --> public: A(int a = 0) :_a(a) {<!-- --> cout << "A():" <<this << endl; } ~A() {<!-- --> cout << "~A(): " <<this << endl; } private: int _a; }; int main() {<!-- --> A* p1 = (A*)malloc(sizeof(A)); // At this time, the space pointed to by p1 has not been initialized. Malloc only has the function of applying for space. new(p1)A; // Use positioning new to construct the p1 object p1->~A(); // The destructor can be called explicitly free(p1); A* p2 = (A*)operator new(sizeof(A)); // operator new also only applies for space and does not initialize the space new(p2)A(2); // Initialize using list p2->~A(); operator delete(p2); return 0; }
Finally, positioning new
was indeed used to complete the initialization and construction of the uninitialized space.
7. The difference between malloc/free and new/delete
What malloc/free
and new/delete
have in common is that they both apply for space from the heap and require the user to release it manually.
The difference is:
malloc
andfree
are functions,new
anddelete
are operators.- The space requested by
malloc
will not be initialized, butnew
can be initialized.- When
malloc
applies for space, you need to manually calculate the space size and pass it.new
only needs to be followed by the type of space. If there are multiple objects,[ ]
Just specify the number of objects.- The return value of
malloc
isvoid*
, which must be forced when used.new
is not needed becausenew
follows is the type of space.- When
malloc
fails to apply for space, it returnsNULL
, so it must be null when used.new
is not required, butnew
code> needs to catch exceptions.- When applying for a custom type object,
malloc/free
will only open up space and will not call the constructor and destructor, whilenew
will call the constructor after applying for space. Initialization of the object,delete
will call the destructor to complete the cleanup of resources in the space before releasing the space.
End of this chapter.