It happens quite too often that a C++ application allocates memory but don't deallocate it. This is the job for the operator to new and delete. Thanks to them both you can explicitly manage the memory management of an application.
From time to time I had to verify for a customer that its application correctly releases its memory. In particular, programs running for a long period of time and often allocate and deallocate memory are a challenge from the memory management perspective. Of course, the automatic release of the memory during the shutdown of the program is not an option.
The baseline
I use as a baseline of my analysis a simple program that quite often allocates and deallocates memory. In production, the code is bigger. That has no effect on my strategy.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
// overloadOperatorNewAndDelete.cpp
// #include "myNew.hpp"
// #include "myNew2.hpp"
// #include "myNew3.hpp"
#include <iostream>
#include <string>
class MyClass{
float* p= new float[100];
};
class MyClass2{
int five= 5;
std::string s= "hello";
};
int main(){
int* myInt= new int(1998);
double* myDouble= new double(3.14);
double* myDoubleArray= new double[2]{1.1,1.2};
MyClass* myClass= new MyClass;
MyClass2* myClass2= new MyClass2;
delete myDouble;
delete [] myDoubleArray;
delete myClass;
delete myClass2;
// getInfo();
}
|
The key question is. Is there a corresponding delete to each new call?
Too careless
The question is quite simple to answer by overloading the global operator new and delete. I count for each operator, how often it was called.
Operator new
C++ offers the operator new in four variations.
void* operator new (std::size_t count );
void* operator new[](std::size_t count );
void* operator new (std::size_t count, const std::nothrow_t& tag);
void* operator new[](std::size_t count, const std::nothrow_t& tag);
The first two variations will throw a std::bad_alloc exception if they can not provide the memory. The last two variations return a null pointer. It's quite convenient that is sufficient to overload only version 1 because versions 2 - 4 use the version 1: void* operator new(std::size_t count). This statement holds also for variants 2 and 4, which are designed for C arrays. You can read the details to the global operator new here: cppreference.com.
The statements hold also for operator delete.
Operator delete
C++ offers six variations for operator delete.
void operator delete (void* ptr);
void operator delete[](void* ptr);
void operator delete (void* ptr, const std::nothrow_t& tag);
void operator delete[](void* ptr, const std::nothrow_t& tag);
void operator delete (void* ptr, std::size_t sz);
void operator delete[](void* ptr, std::size_t sz);
According to operator new it is sufficient to overload for operator delete the first variant because the remaining 5 use void operator delete(void* ptr) as a fallback. Only a word about the two last versions of operator delete. You have in this version the length of the memory block in the variable sz to your disposal. Read the details here at cppreference.com.
This time I use the program overloadOperatorNewAndDelete.cpp the header myNew.hpp (line 3). The same holds for lines 34. Here I invoke the function getInfo to get information about my memory management.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
// myNew.hpp
#ifndef MY_NEW
#define MY_NEW
#include <cstdlib>
#include <iostream>
#include <new>
static std::size_t alloc{0};
static std::size_t dealloc{0};
void* operator new(std::size_t sz){
alloc+= 1;
return std::malloc(sz);
}
void operator delete(void* ptr) noexcept{
dealloc+= 1;
std::free(ptr);
}
void getInfo(){
std::cout << std::endl;
std::cout << "Number of allocations: " << alloc << std::endl;
std::cout << "Number of deallocations: " << dealloc << std::endl;
std::cout << std::endl;
}
#endif // MY_NEW
|
I create in the file two static variables alloc and dealloc (line 10 and 11). They keep tracking of how often I used the overloaded operator new (line 13) and operator delete (line 18). I delegate in the functions the memory allocation to std::malloc and the memory deallocation to std::free. The function getInfo (lines 23 - 31) provides me with the numbers and displays them.
The question is. Have I cleaned everything clean?

Of course, not. That was the intention of this and the following post. Now I know, that I have leaks. Maybe it helps to determine the addresses of the objects, which I have forgotten to clean up.
Addresses of the memory leaks.
So, I have to put more cleverness into the header myNew2.hpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
// myNew2.hpp
#ifndef MY_NEW2
#define MY_NEW2
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <new>
#include <string>
#include <array>
int const MY_SIZE= 10;
std::array<void* ,MY_SIZE> myAlloc{nullptr,};
void* operator new(std::size_t sz){
static int counter{};
void* ptr= std::malloc(sz);
myAlloc.at(counter++)= ptr;
return ptr;
}
void operator delete(void* ptr) noexcept{
auto ind= std::distance(myAlloc.begin(),std::find(myAlloc.begin(),myAlloc.end(),ptr));
myAlloc[ind]= nullptr;
std::free(ptr);
}
void getInfo(){
std::cout << std::endl;
std::cout << "Not deallocated: " << std::endl;
for (auto i: myAlloc){
if (i != nullptr ) std::cout << " " << i << std::endl;
}
std::cout << std::endl;
}
#endif // MY_NEW2
|
The key idea is it to use the static array myAlloc (line 15) to keep track of the addresses of all std::malloc (line 19) and std::free (line 19) invocations. Of course, I can not use the function operator new container that needs dynamic memory. This container would invoke the operator new. A recursion that would cause my program to crash. Therefore, I use a std::array in line 15, because std::array gets its memory at compile time. Now it can happen, that my std::array becomes too small. Therefore, I invoke myAlloc.at(counter++) for checking the array boundaries.
Which memory address have I forgotten to release? The output gives the answer.

A simple search for the object having the address is no good idea. Because it is quite probable that a new call of std::malloc reuse an already used address. That is ok if the objects have been deleted in the meantime.
But why are the addresses part of the solution? I have only to compare the memory address of the created objects with the memory address of the not deleted objects.
Comparison of the memory addresses
In addition to the memory address, I have the size of the reserved memory at my disposal. I use this information in operator new.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
// myNew3.hpp
#ifndef MY_NEW3
#define MY_NEW3
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <new>
#include <string>
#include <array>
int const MY_SIZE= 10;
std::array<void* ,MY_SIZE> myAlloc{nullptr,};
void* operator new(std::size_t sz){
static int counter{};
void* ptr= std::malloc(sz);
myAlloc.at(counter++)= ptr;
std::cerr << "Addr.: " << ptr << " size: " << sz << std::endl;
return ptr;
}
void operator delete(void* ptr) noexcept{
auto ind= std::distance(myAlloc.begin(),std::find(myAlloc.begin(),myAlloc.end(),ptr));
myAlloc[ind]= nullptr;
std::free(ptr);
}
void getInfo(){
std::cout << std::endl;
std::cout << "Not deallocated: " << std::endl;
for (auto i: myAlloc){
if (i != nullptr ) std::cout << " " << i << std::endl;
}
std::cout << std::endl;
}
#endif // MY_NEW3
|
Now, the allocation and deallocation of the application are clearly more transparent.

A simple comparison shows. I forget to release an object with 4 bytes and an object with 400 bytes. In addition, the sequence of allocation in the source code corresponds to the sequence of outputs in the program. Now, it should be quite easy to identify the missing memory releases.
What's next?
The program is not beautiful in two ways. First, I statically allocate the memory for std::array; second, I want to know, which object was not released. In the next post, I will solve both issues.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Dominik Vošček, and Rob North.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.
My special thanks to Embarcadero 
My special thanks to PVS-Studio 
My special thanks to Tipi.build 
Seminars
I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
Bookable (Online)
German
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ - The Core Language
- C++ - The Standard Library
- C++ - Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
New
- Clean Code with Modern C++
- C++20
Contact Me
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: This email address is being protected from spambots. You need JavaScript enabled to view it.
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++,

Read more...