Article directory
foreword
If you are interested in C++ learning, you can read this article: C/C++ Tutorial
1. new/delete
1. Preamble
In C++ programming, dynamic memory allocation is a very common operation. new and delete are dynamic memory allocation operators provided in C++, they can be used to dynamically allocate any type of memory, and do not need to explicitly specify the size of the memory block.
2. How to use
2.1. Basic syntax of new and delete
new and delete are keywords in C++ for dynamically allocating and freeing memory. The basic syntax for new and delete is as follows:
// 动态分配一个对象
Type* p = new Type;
// 释放已经分配的对象
delete p;
Among them, Type
represents the data type to be dynamically allocated, p
and is a pointer to the data type. When new Type
the operation , the system will allocate a block of memory for this type of object and return a pointer to this memory block. When the object is no longer needed, the memory can be released through delete
the operation .
If you need to allocate multiple objects at the same time, you can use the following syntax:
// 动态分配一个数组
Type* p = new Type[n];
// 释放已经分配的数组
delete [] p;
Among them, n
represents the number of objects to be allocated, p
and is a pointer to an array of Type
type .
It should be noted that when using new
for dynamic memory allocation, if there is insufficient memory, std::bad_alloc
an exception will be thrown. Therefore, this exception should be handled in the program.
2.2. The underlying implementation principle of new and delete
New and delete also have some details to pay attention to in the underlying implementation. When performing new Type
the operation , the following steps are actually carried out in sequence:
- Call the operator new function to apply for a piece of memory with a size
sizeof(Type)
of . - Call the constructor of the class to initialize the requested memory space.
- Returns a pointer to the requested memory space.
When performing delete p
the operation , the following steps are actually carried out in sequence:
- Call the destructor of the class to release the resources occupied by the object.
- Call the operator delete function to release the memory occupied by the object.
Among them, operator new and operator delete are keywords provided in C++. The operator new function is responsible for applying for memory, while the operator delete function is responsible for releasing memory.
It should be noted that, unlike malloc/free, new/delete can call the constructor and destructor of the class, and automatically calculate the required memory space size. This is also a big advantage of using new/delete.
3. The underlying principle
3.1. operator new 和 operator delete
The operator new function and operator delete function in C++ are used to dynamically allocate and release memory. The operator new function is responsible for applying for memory, while the operator delete function is responsible for releasing memory.
Here is one implementation of operator new:
void* operator new(size_t size) {
if (size == 0) {
size = 1;
}
void* ptr = malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
return ptr;
}
Among them, size
indicates the size of the memory space to be applied. If the value is 0, set it to 1. Then call the malloc function to apply for a specified size of memory space, if the application fails, std::bad_alloc
an exception .
The following is an implementation of operator delete:
void operator delete(void ptr) noexcept {
free(ptr);
}
Where ptr
is the memory space pointer to be freed. noexcept
The keyword is used here to indicate that the function will not throw any exceptions.
Note that when using operator new and operator delete functions, you need to call the constructor and destructor of the class yourself.
3.2. The underlying implementation principles of new and delete
The new and delete keywords actually encapsulate and overload the operator new and operator delete functions in the underlying implementation, for the convenience of programmers. Here's one implementation of new and delete:
void* operator new(size_t size) {
if (size == 0) {
size = 1;
}
void* ptr = malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
return ptr;
}
void operator delete(void* ptr) noexcept {
free(ptr);
}
void* operator new[](size_t size) {
if (size == 0) {
size = 1;
}
void* ptr = malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
return ptr;
}
void operator delete[](void* ptr) noexcept {
free(ptr);
}
As you can see, new and delete actually overload operator new and operator delete.
Note that for complex data structures, when using new[] to apply for multiple memories, an additional piece of 4-byte memory will be applied for storing the number of current applications. Use delete[] to know how many times the destructor of the object is called. But this data is not visible to the outside world
4. Precautions
When using new/delete for dynamic memory allocation, you need to pay attention to the following points:
- Memory leaks: Memory that is no longer used must be released in time, otherwise memory leaks may result.
- Dangling pointer: The memory block pointer that has been freed can no longer be accessed, otherwise it may cause the program to crash or other unpredictable errors.
- Do not release memory repeatedly: the same memory block can only be released once, otherwise it may cause program crashes or other unpredictable errors.
- Multi-threaded environment: When multiple threads access the same block of memory at the same time, it is necessary to adopt an appropriate synchronization mechanism to ensure thread safety.
5. Summary
In C++ programming, the appropriate dynamic memory allocation method should be selected according to the specific situation. When using dynamic memory allocation, good programming habits should be followed to ensure the correctness and stability of the program. At the same time, it is also necessary to avoid problems such as memory leaks, dangling pointers, and repeated release of memory to ensure the robustness and stability of the program.
Two, malloc/free
1. Preamble
malloc and free are dynamic memory allocation functions provided in C, they can be used to dynamically allocate any type of memory, and do not need to explicitly specify the size of the memory block
2. How to use
2.1. The basic syntax of malloc and free
malloc and free are functions in C that are used to dynamically allocate and free memory. The following is the basic syntax of malloc and free:
// 动态分配一块内存
Type* p = (Type*)malloc(sizeof(Type));
// 释放已经分配的内存
free(p);
Among them, Type
represents the data type to be dynamically allocated, p
and is a pointer to the data type. When malloc(sizeof(Type))
the operation , the system will allocate a block of memory for this type of object and return a pointer to this memory block. When the object is no longer needed, the memory can be released through free
the operation .
It should be noted that when using malloc
for dynamic memory allocation, if insufficient memory occurs, a null pointer will be returned. Therefore, this situation should be handled in the program.
2.2. The underlying implementation principle of malloc and free
Malloc and free also have some details to pay attention to in the underlying implementation. When performing malloc(sizeof(Type))
the operation , the following steps are actually carried out in sequence:
- Call the system function sbrk to expand the data segment of the program. (windows will call win API to achieve this function)
- Link the requested memory block with the used memory block.
- Returns a pointer to the requested memory space.
When performing free(p)
the operation , the following steps are actually carried out in sequence:
- Marks the block of memory pointed to by p as unused.
- Merges the memory block pointed to by p with other unused memory blocks.
- If the merged memory block is not occupied, the memory block is released.
It should be noted that when using malloc/free for dynamic memory allocation, you need to call the constructor and destructor of the class yourself, and you cannot calculate the required memory space.
3. The underlying principle
3.1. sbrk function
The sbrk function is a system call used to expand the program's data segment. In Linux systems, the sbrk function can return the current heap top address, and can move the heap top address up or down by the specified number of bytes.
The following is a simple example that demonstrates how to use the sbrk function to obtain the current heap top address:
#include <unistd.h>
#include <iostream>
int main() {
void* p1 = sbrk(0); // 获取当前堆顶部地址
std::cout << "p1 = " << p1 << std::endl;
void* p2 = sbrk(1024); // 将堆顶部地址向上移动 1024 字节
std::cout << "p2 = " << p2 << std::endl;
void* p3 = sbrk(-512); // 将堆顶部地址向下移动 512 字节
std::cout << "p3 = " << p3 << std::endl;
void* p4 = sbrk(0); // 再次获取当前堆顶部地址
std::cout << "p4 = " << p4 << std::endl;
return 0;
}
The window system also has its own win API that can be used to allocate heap memory
3.2. Memory block management
malloc and free also need to manage memory blocks in the underlying implementation. When using malloc for dynamic memory allocation, the system will add some additional information to the requested memory block
For example, the size of the memory block, a pointer to the next memory block, etc. These information will be saved at the beginning of the memory block and will not affect the user program's access to the memory space.
The following is a simple example that demonstrates how to obtain a block of memory through the malloc function, and the information contained in the memory block:
#include <iostream>
#include <cstdlib>
int main() {
int* p = (int*)malloc(sizeof(int) * 10); // 动态分配一块内存,可以存放 10 个 int 类型的变量
if (!p) {
std::cout << "Memory allocation failed" << std::endl;
return -1;
}
std::cout << "Allocate memory at address " << p << std::endl;
std::cout << "The size of the memory block is " << sizeof(int) * 10 << " bytes" << std::endl;
int* next_p = (int*)(((char*)p) + sizeof(int) * 10);
std::cout << "The pointer to the next memory block is " << next_p << std::endl;
free(p); // 释放内存
return 0;
}
3.3. Memory Alignment
When using malloc for dynamic memory allocation, you need to consider the issue of memory alignment.
The so-called memory alignment means that the address where the data type is placed in the memory must meet certain conditions.
Specifically, each data type has an alignment associated with it, which is usually equal to the size of the data type (for example, an int has an alignment of 4 bytes). When allocating memory, the system will ensure that the starting address of the requested memory block is an integer multiple of the alignment value.
The following is a simple example that demonstrates how to obtain a block of memory through the malloc function and demonstrates the effect of memory alignment:
#include <iostream>
#include <cstdlib>
struct MyStruct {
double x;
char c;
int i;
};
int main() {
std::cout << "Size of MyStruct is " << sizeof(MyStruct) << " bytes" << std::endl;
MyStruct* p1 = (MyStruct*)malloc(sizeof(MyStruct));
if (!p1) {
std::cout << "Memory allocation failed" << std::endl;
return -1;
}
std::cout << "Allocate memory at address " << p1 << std::endl;
char* p2 = (char*)p1;
for (int i = 0; i < sizeof(MyStruct); ++i) {
std::cout << (int)p2[i] << " ";
}
std::cout << std::endl;
free(p1); // 释放内存
return 0;
}
It can be seen that when allocating memory of type MyStruct, the system will ensure that the returned starting address is an integer multiple of the size of type double.
4. Precautions
When using malloc/free for dynamic memory allocation, you need to pay attention to the following points:
- Memory leaks: Memory that is no longer used must be released in time, otherwise memory leaks may result.
- Dangling pointer: The memory block pointer that has been freed can no longer be accessed, otherwise it may cause the program to crash or other unpredictable errors.
- Do not release memory repeatedly: the same memory block can only be released once, otherwise it may cause the program to crash or
Other unpredictable errors.
- Memory out-of-bounds: Accessing a freed memory block, or accessing an address beyond the range of the allocated memory block, may cause the program to crash or other unpredictable errors.
- Do not mix malloc/free and new/delete: One memory allocation method should be uniformly used in the same program, do not mix malloc/free and new/delete, otherwise it may cause memory management problems.
5. The difference between new/delete and malloc/free
new and delete are dynamic memory allocation operators provided in C++, they are functionally similar to malloc/free.
The use of new/delete is simpler and more intuitive than malloc/free. In addition, new/delete has the following advantages:
- Type safety: new/delete can automatically calculate the required memory space size according to the type, without manual specification.
- Automatically call the constructor and destructor: new can automatically call the constructor of the class, and delete can automatically call the destructor of the class, which makes it easier to manage the life cycle of the object.
- Support overloading: new/delete operators can be overloaded, so that some special functions can be realized.
It should be noted that when using new/delete for dynamic memory allocation, problems such as memory leaks, dangling pointers, and memory out-of-bounds may also occur. Therefore, when writing a program, the problem of dynamic memory allocation and release must be carefully handled to avoid the above problems.
6. Summary
In the process of using dynamic memory allocation, you need to pay attention to problems such as memory leaks, dangling pointers, and memory out-of-bounds, and you also need to choose an appropriate memory allocation method according to the specific situation.