Listings Grimm/C++-Tricks: Memory Leak Detection

Listing 1: Code mit Speicherlecks

// #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();
}

-------

Listing 2: `new`- und `delete`-Aufrufe mitzählen

#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

-------

Listing 3: Nicht freigegebene Speicherbereiche finden

#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

-------

Listing 4: Ein Makro liefert detaillierte Info

#include "myNew4.hpp"
// #include "myNew5.hpp"

#define new new(__FILE__, __LINE__)

#include <iostream>
#include <new>
#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;

  dummyFunction();

  getInfo();
}

-------

Listing 5: Auswertung von Zeilennummer und Dateiname

#ifndef MY_NEW4
#define MY_NEW4

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <new>
#include <array>

int const MY_SIZE = 10;
int counter = 0;
std::array<void* ,MY_SIZE> myAlloc{nullptr,};

void* newImpl(std::size_t sz,char const* file, int line) {
  void* ptr= std::malloc(sz);
  std::cerr << file << ": " << line << " " <<  ptr << std::endl;
  myAlloc.at(counter++)= ptr;
  return ptr;
}

void* operator new(std::size_t sz,char const* file, int line) {
  return newImpl(sz,file,line);
}

void* operator new [](std::size_t sz,char const* file, int line) {
  return newImpl(sz,file,line);
}

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);
}

#define new new(__FILE__, __LINE__)

void dummyFunction() {
  int* dummy= new int;
}

void getInfo() {
  std::cout << std::endl;
  std::cout << "Allocation: " << std::endl;
  for (auto i: myAlloc){
      if (i != nullptr ) std::cout << " " << i << std::endl;
  }
  std::cout << std::endl;
}

#endif // MY_NEW4

-------

Listing 6: Die finale Lösung

#ifndef MY_NEW5
#define MY_NEW5

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <new>
#include <string>
#include <vector>

std::vector<void*> myAlloc;

void* newImpl(std::size_t sz,char const* file, int line) {
  static int counter{};
  void* ptr = std::malloc(sz);
  std::cerr << file << ": " << line << " " <<  ptr << std::endl;
  myAlloc.push_back(ptr);
  return ptr;
}

void* operator new(std::size_t sz,char const* file, int line) {
  return newImpl(sz,file,line);
}

void* operator new [](std::size_t sz,char const* file, int line) {
  return newImpl(sz,file,line);
}

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);
}

#define new new(__FILE__, __LINE__)

void getInfo() {
  std::cout << std::endl;
  std::cout << "Allocation: " << std::endl;
  for (auto i: myAlloc){
      if (i != nullptr ) std::cout << " " << i << std::endl;
  }
  std::cout << std::endl;
}

#endif // MY_NEW5
