To manage dynamic memory, C++ provides two operators new and delete to allocate and free memory, respectively.
In C++, memory can be managed in two main ways:
Automatic memory: It is automatically allocated when a local or global variable is declared and is automatically freed when the variable goes out of scope.
Dynamic memory: It is manually allocated and freed by the programmer during program execution using the
newanddeleteoperators.
Basically, dynamic memory is storage space that we need, but we don’t know how much we need until runtime (for example, because it depends on system input).
Unlike automatic memory, memory allocated with new persists until it is explicitly freed using delete.
What is new
The new operator in C++ is used to allocate dynamic memory (that is, to tell the system “hey, give me a place to store this”).
data_type* pointer = new data_type;
- data_type: The type of data for which memory is being allocated.
- pointer: A pointer that will store the address of the allocated memory.
Let’s see it with an example,
int* p = new int; // Allocates memory for an integer
*p = 5; // Stores the value 5 in the allocated memory
std::cout << *p << std::endl; // Prints 5
In this example,
- Memory is allocated for an integer
- The pointer
ppoints to that memory - The value
5is stored at that memory location. - Through it we can access the stored value.
What is delete
The delete operator is used to free memory that was dynamically allocated with new.
delete pointer;
- pointer: The pointer that points to the memory that should be freed.
Let’s see it with an example
int* p = new int; // Allocates memory for an integer
*p = 5; // Stores the value 5 in the allocated memory
delete p; // Frees the memory
p = nullptr; // Prevents the pointer from pointing to freed memory
In this example,
- After using the allocated memory, it is freed with
delete nullptris assigned to the pointer to prevent it from pointing to a memory address that is no longer valid.
Common errors when using new and delete
The most common error is forgetting to do a delete when we no longer need a variable, or when we are going to allocate it again.
void memoryLeak() {
int* p = new int; // Allocates memory for an integer
// Forgetting to free the memory
p = new int; // Reallocating memory
}
In this case, the pointer p is destroyed when exiting the function, but the allocated memory is not freed, causing a leak.
This is called a memory leak and is a very common error.
This leads to the program consuming more and more memory and, eventually, going boom 💥 (and it’s also sloppy programming).
The memory will be freed when the program closes in any case. Don’t think it’s a permanent thing for the system.
Another common error is accessing memory that has already been freed with delete, which will also cause an error in your program.
int* p = new int(10);
delete p; // Frees the memory
*p = 5; // Error: accessing freed memory
This example shows an access to memory after it has been freed, which can cause another boom in your program 💥.
Freeing the same memory more than once is another common error, known as double free.
void doubleFree() {
int* p = new int(10);
delete p;
delete p; // Error: double freeing
}
In this case, an attempt is made to free the same memory twice, which is a serious error.
Best Practices
Pair new and delete
Every time new is used to allocate memory, there should most likely be a corresponding delete somewhere to free that memory.
Use nullptr after delete
After freeing memory with delete, it is good practice to assign nullptr to the pointer. This prevents accidental access to freed memory.
delete p;
p = nullptr;
Use smart pointers
Instead of manually managing dynamic memory with new and delete, it is recommended to use smart pointers like std::unique_ptr and std::shared_ptr, which automatically manage memory and help prevent memory leaks and invalid accesses.
Do not over-allocate memory
It is important to carefully allocate the necessary amount of memory (don’t allocate wildly).
After all, it is a limited resource, and as with any resource, its use should be reduced if not necessary.
