自己实现简易的内存泄露检测工具VLD

有一个很著名的内存泄露检测工具 Visual leak detected 想必大家都不陌生,但今天我们可以自己写一个简易版的。哈哈,自己动手,丰衣足食有木有!

它的原理就是我们重载了操作符 newdelete,当用 new 开辟空间的时候,就将这块空间串到我们定义的结构体 MEMNode 形成的链表中,(在main程序结束时,用 check_vld() 函数检测有没有内存泄露)但我觉得,如果我们动态开辟了一个对象,在它的析构函数里用 delete 释放的话,这种方法就不太可行。因为析构函数只有到 return 时才会被调用(在 check_vld() 函数之前)。检测结果就不准确。由此我想到,可以将这个结构体改为 C++ 中的 class,并将其指针也封装为一个类 PMEMNode,然后定义一个 PMEMNode 的全局静态成员(它会在主函数之前被构造,主函数结束后析构)。并将 check_vld() 的代码放在他的析构函数中。

废话不多说,代码在下面:

//vld.h:
#pragma once

#include <iostream>
using namespace std;

class MemNode {
    friend void* operator new(size_t sz, char *filename, int line);
public:
    MemNode(int s = 0,char *pf = NULL, int l = 0,class MemNode *pl=NULL)
        :size(s),file(pf),line(l),link(pl)
    {}
    ~MemNode()
    {}
    void set(int sz, char *pf, int l, class MemNode *pl)
    {
        size = sz;
        file = pf;
        line = l;
        link = pl;
    }
    void setlink(MemNode *pl)
    {
        link = pl;
    }
    int getsize()
    {
        return size;
    }
    char *getfile()
    {
        return file;
    }
    int getline()
    {
        return line;
    }
    MemNode *getlink()
    {
        return link;
    }
    private:
        int size;
        char *file;
        int line;
        class MemNode *link;
};

void check_vld();

class pMemNode {
public:
    pMemNode(MemNode *ptr=NULL):p(ptr){}
    ~pMemNode()
    {
        check_vld();
    }
    MemNode *getptr()
    {
        return p;
    }
    void setptr(MemNode *ptr)
    {
        p = ptr;
    }
private:
    MemNode *p;
};

static pMemNode _AfxMem;

void* operator new(size_t sz,char *filename,int line)
{
    void *result=NULL;
    int total_size = sz + sizeof(MemNode);
    MemNode *p = new MemNode[total_size];
    p->set(sz, filename, line, NULL);
    if (_AfxMem.getptr() == NULL)
    {
        _AfxMem.setptr(p);
    }
    else
    {
        p->setlink(_AfxMem.getptr());
        _AfxMem.setptr(p);
    }
    result = _AfxMem.getptr()+1;
    return result;
}

void operator delete(void *ptr)
{
    if(_AfxMem.getptr()==NULL)
    {
        return;
    }
    if(ptr==NULL)
    {
        return;
    }
    MemNode *p;
    if (_AfxMem.getptr()+1 == ptr)
    {
        p = _AfxMem.getptr();
        _AfxMem.setptr(p->getlink());
        delete p;
    }
    else
    {
        p = _AfxMem.getptr();
        while (p->getlink() != NULL &amp;&amp; p->getlink()+1!=ptr)
        {
            p = p->getlink();
        }
        if (p->getlink() != NULL)
        {
            MemNode *q = p->getlink();
            p->setlink(q->getlink());
            delete q;
        }
    }
}

void check_vld()
{
    if (_AfxMem.getptr() == NULL)
    {
        cout << \"No memory Leaks detected.\" << endl;
    }
    else
    {
        MemNode *p = _AfxMem.getptr();
        cout << \"WARNING: Visual Leak Detector detected memory leaks!\" << endl;
        while (p != NULL)
        {
            printf(\"At %p: %d Bytesn\", p + 1, p->getsize());
            printf(\"file: %s, line: %dn\", p->getfile(), p->getline());
            p = p->getlink();
        }
    }
}
//Main.cpp:

#include <iostream>
#include <string>
#include \"vld.h\"
using namespace std;

class Test
{
public:
    Test(char *str)
    {
        int a = strlen(str) + 1;
        ch = new(__FILE__, __LINE__) char[a];
        //strcpy(ch, str);
    }
    ~Test()
    {
        delete[]ch;
        ch = NULL;
    }
private:
    char *ch;
    int a;
    double b;
    char c;
};

int main()
{
    //VLD vld;
    int a = 10;
    Test t(\"hello\");
    //int *p = new(__FILE__,__LINE__) int(10);
    //double *q = new(__FILE__,__LINE__) double(12.34);
    Test *s = new(__FILE__,__LINE__) Test(\"hello\");

    //delete p;
    //delete q;
    //check_vld();
    return 0;
}