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

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

它的原理就是我们重载了操作符new和delete,当用new开辟空间的时候,就讲这块空间串到我们定义的结构体MEMNode形成的链表中,(这是老师的写法,在main程序结束时,用check_vld()函数检测有没有内存泄露)但我觉得,如果我们动态开辟了一个对象,在它的析构函数里用delete释放的话,这种方法就不太可行。因为析构函数只有到return时才会被调用(在check_vld()函数之前)。检测结果就不准确。由此我想到,可以将这个结构体该为C++中的类class MEMNode,并将其指针也封装为一个类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 && 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();
        }
    }
}
1
2
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; }