Monday, April 30, 2012

How to Add a Simple Memory Leak Test to a C++ Project

The following code illustrates a simple test for memory leaks in C++ programs that allocate memory through the new operator.  The basic trick is to override the new and delete operators and count the number of times each are called; at the completion of your test code, the number of times new is called should equal the number of times delete is called, otherwise, your code is leaking memory.  (This is not a process I invented, but found discussed across the Web.)

You can add this test to your projects using the following 2-step process.

Step 1: Create a file with the following contents and add it to the build.

// How to test for memory leaks in C++ programs
// that allocate memory through the new operator. 
//
// Author: David Turner (of CSUSB)
//


#include <memory>
#include <stdlib.h>


////////////////////////////////////////////////////////////////
//                                                            //
// Override the new and delete operators to keep track of     //
// the number of times they are called.                       //
//                                                            //
// If there is no memory leak, then the number of times new   //
// is called will equal the number of times delete is called  //
// after all destructors run.                                 //
//                                                            //
////////////////////////////////////////////////////////////////


unsigned int newCalls = 0;
unsigned int deleteCalls = 0;




#ifdef _WIN32


    void * operator new(size_t size)
    {
        void * p = malloc(size);
        if (!p) throw "operator new() failed";
        ++newCalls;
        return p;
    }


    void * operator new[](size_t size)
    {
        void * p = malloc(size);
        if (!p) throw "operator new() failed";
        ++newCalls;
        return p;
    }


#else


    void * operator new(size_t size) throw(std::bad_alloc) 
    {
        void * p = malloc(size);
        if (!p) throw std::bad_alloc();
        ++newCalls;
        return p;
    }


    void * operator new[](size_t size) throw(std::bad_alloc) 
    {
        void * p = malloc(size);
        if (!p) throw std::bad_alloc();
        ++newCalls;
        return p;
    }


#endif

void operator delete(void * p) throw()  
{
    if (p != NULL)
    {
        ++deleteCalls;
        free(p);
    }
}


void operator delete[](void * p) throw() 
{
    if (p != NULL)
    {
        ++deleteCalls;
        free(p);
    }
}


Step 2:  Move your test code into a function called test and then use the following for your main function.

int main(int argc, const char * argv[])
{
    extern unsigned int newCalls;
    extern unsigned int deleteCalls;
    
    test();
    assert(newCalls == deleteCalls);
        
    std::cout << "All tests passed." << std::endl;
    return 0;
}

Putting all test code in function test is needed so that objects allocated on the heap have their destructors called.



No comments: