What is a memory leak in C++?

A memory leak in C++ is a coding problem that occurs if we don't release dynamically allocated memory after it is no longer needed. When memory is allocated but not deallocated, the program consumes unnecessary memory, leading to reduced performance and responsiveness. A memory management flow in our program should look like the following:

Memory management flow
Memory management flow

Allocation and deallocation of dynamic memory

To allocate the dynamic memory in C++, we use the new operator.

int A = new int(5);

To deallocate the dynamic memory in C++, we use the delete operator.

delete A;

The following diagram will help us understand the allocation and deallocation of dynamic memory:

Dynamic memory allocated for an integer A
1 of 3

Note: The unreleased dynamic memory is not permanently wasted, as the system's operating system eventually reclaims it when the program exits, but it can still cause multiple wastage problems during program execution.

Reasons for memory leaks in C++

Let's discuss some of the reasons that cause memory leaks in C++.

1. Missing the delete operator

Memory leaks mostly happen when we forget to deallocate the dynamic memory we allocate after we use it.

#include <iostream>
using namespace std;
int main() {
int * A = new int [5];
//apply operation on A
return 0;
}

In the code above, we dynamically allocate memory for an integer array A with a size of 5 elements in line 5. After performing operations on this array, we forget to deallocate it using the delete operator.

Solution

The correct solution for the code above will be to use the delete operator in line 7 to release the dynamic memory, which is no longer needed.

#include <iostream>
using namespace std;
int main() {
int * A = new int [5];
//apply operation on A
delete[] A;
return 0;
}

2. Incorrect use of the delete operator

In some cases, we use the delete operator incorrectly while deallocating the dynamic memory. For instance, if we allocate a dynamic 1D array memory using the new[] operator, the memory should be deallocated using the delete[] operator.

#include <iostream>
using namespace std;
int main() {
int * A = new int [5];
//apply operation on A
delete A;
return 0;
}

In the code above, we dynamically allocate memory for an integer array A with a size of 5 elements in line 5. After performing operations on this array, we delete it in line 7 without the [] square brackets so only the first element of the array is deleted, as the delete operator without the brackets deletes a single object.

Solution

The correct solution for the above code will be to use the delete operator with the [] square brackets in line 7 to release the dynamic memory, which is no longer needed.

#include <iostream>
using namespace std;
int main() {
int * A = new int [5];
//apply operation on A
delete[] A;
return 0;
}

3. Exceptions before deallocation

When an exception is thrown in our code, and the delete operator is written after the exception-causing statement, our code will skip all the next code and jump directly to the catch block. As a result, the program loses the opportunity to release the memory, causing a memory leak.

#include <iostream>
#include <stdexcept>
using namespace std;
int main() {
try{
int * A = new int (5);
throw runtime_error("An exception is thrown!");
delete A;
}
catch (runtime_error& e){
//Dealing with the error
}
return 0;
}

In the code above, we dynamically allocate memory for an integer A with the value 5 in line 7, inside the try block. An exception is thrown in line 8, so the code jumps directly to the catch block, skipping the statements for deallocating our dynamic memory.

Solution

The correct solution for the above code will be to use the delete operator before any exception-causing statements to be safe.

#include <iostream>
#include <stdexcept>
using namespace std;
int main() {
try{
int * A = new int (5);
delete A;
throw runtime_error("An exception is thrown!");
}
catch (runtime_error& e){
//Dealing with the error
}
return 0;
}

4. Unreachable memory

Sometimes, memory may become unreachable due to programming errors or unexpected program flow. This can cause memory leaks as the program loses the ability to deallocate that memory.

#include <iostream>
using namespace std;
int main() {
int * A = new int (5);
bool condition = false;
if (condition) {
delete A; // This delete statement will not be executed if the condition is false
}
return 0;
}

In the code above, we dynamically allocate memory for an integer A with the value 5 in line 5. We release this memory inside a condition in line 8. So whenever the condition is satisfied, our memory will be deleted, which leads to the risk of memory leakage.

Solution

The correct solution for the code above will be releasing the memory outside the if condition in line 6.

#include <iostream>
using namespace std;
int main() {
int * A = new int (5);
delete A;
bool condition = false;
if (condition) {
// working in the condition
}
return 0;
}

How to avoid memory leaks in C++

To avoid memory leaks, we should follow best practices in memory management. Additional C++ features like smart pointers, unique_ptr, and shared_ptr can significantly reduce the risk of memory leaks as they automatically manage memory deallocation.

The following code demonstrates how to allocate dynamic memory using unique_ptr in C++.

#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int> A(new int(5));
//perform operations on dynamic memory
return 0;
}

In the code above, we first include the header file memory in our code so we can use the unique_ptr. Then, we dynamically allocate memory for an integer A with the value 5 in line 6 using the unique_ptr. This memory will be automatically deallocated when our main function is returned.

Conclusion

Memory leaks in C++ occur when dynamically allocated memory is not properly deallocated, leading to the wastage of system resources and potential instability of the program. A memory leak can happen due to various programming errors. We should be mindful of these errors and carefully manage memory to ensure better resource utilization.

Copyright ©2024 Educative, Inc. All rights reserved