How to Avoid Memory Leaks in C++
-
Use the
delete
Operator to Free Eachnew
-Allocated Memory Block -
Use
std::unique_ptr
to Automatically Free Heap Objects
This article will demonstrate multiple methods about how to avoid memory leaks in C++.
Use the delete
Operator to Free Each new
-Allocated Memory Block
Memory leaks are a common problem for the programs that directly interact with the raw dynamic memory interface, which puts a burden on the programmer to free each allocated memory with the corresponding method. There are multiple interfaces for memory management accessible in C++ along with some platform-specific system calls, which essentially represent the lowest level functions that can be utilized for this purpose. In most cases, the regular program should only use language-specific facilities like new
and delete
operators for manual memory management or use smart pointers for automatic memory deallocation.
The most vulnerable method for memory leaks is using the new
/delete
operators to directly manage heap memory. Note that every pointer returned from the new
call should be passed to the delete
operator to release the corresponding memory blocks back to the system, or the memory might get exhausted. For example, the following program allocates a 10-element char
array and does not free it before the program exit. Thus, the program is said to suffer from a memory leak.
#include <iostream>
using std::cout;
using std::endl;
constexpr int SIZE = 10;
int main() {
char *arr = new char[SIZE];
for (int i = 0; i < SIZE; ++i) {
arr[i] = (char)(65 + i);
cout << arr[i] << "; ";
}
cout << endl;
return EXIT_SUCCESS;
}
Memory leaks can be detected using the valgrind
program, which is a command-line utility and can be executed on a compiled program file. Note that Valgrind
is actually a set of multiple tools, one of which happens to be a memory checking utility. The following command can be issued to investigate memory leaks.
valgrind --tool=memcheck --leak-check=full ./program
Once it has done checking, the following output is printed. Notice that, since we did not call delete
on the arr
pointer, the whole array resulted in unfreed memory hence the record - definitely lost: 10 bytes
in leak summary. The latter is the actual size of the 10-element char array.
==13732== HEAP SUMMARY:
==13732== in use at exit: 10 bytes in 1 blocks
==13732== total heap usage: 3 allocs, 2 frees, 73,738 bytes allocated
==13732==
==13732== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13732== at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==13732== by 0x1091FE: main (tmp.cpp:11)
==13732==
==13732== LEAK SUMMARY:
==13732== definitely lost: 10 bytes in 1 blocks
==13732== indirectly lost: 0 bytes in 0 blocks
==13732== possibly lost: 0 bytes in 0 blocks
==13732== still reachable: 0 bytes in 0 blocks
==13732== suppressed: 0 bytes in 0 blocks
==13732==
==13732== For lists of detected and suppressed errors, rerun with: -s
==13732== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Use std::unique_ptr
to Automatically Free Heap Objects
The previous example code issue can be fixed by the delete [] arr;
statement before the program exits. Although, another option is to utilize one of the smart pointers e.g. std::unique_ptr
. Smart pointer object can be initialized with the given type and stores the pointer returned from the new
operator. The only difference from the regular pointer is that std::unique_ptr
associated memory region does not need to be deleted
explicitly. Instead, the compiler takes care of the deallocation once the object goes out of the scope.
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
constexpr int SIZE = 10;
int main() {
std::unique_ptr<char[]> arr(new char[SIZE]);
for (int i = 0; i < SIZE; ++i) {
arr[i] = (char)(65 + i);
cout << arr[i] << "; ";
}
cout << endl;
return EXIT_SUCCESS;
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook