How to Avoid Memory Leaks in C++

Jinku Hu Feb 02, 2024
  1. Use the delete Operator to Free Each new-Allocated Memory Block
  2. Use std::unique_ptr to Automatically Free Heap Objects
How to Avoid Memory Leaks in C++

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;
}
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Related Article - C++ Memory