The very first thing you need to do is tell the compiler that you want to track memory allocations, and then include the standard headers and the CRT debugging headers. These 3 lines accomplish this:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
To be of really effective use, those lines need to be included in *every* file, which can be a bit of a pain. As such, it's actually easier to create dedicated header file (I called mine "debug.h") and do not add it to your VS solution. Rather, just let it sit idly by in the root folder of your project, and use the project properties to force the pre-processor to automatically include it in every file.
(Go to Project Properties, select the "Debug" configuration, then go to "Configuration Properties" -> "C/C++" -> "Advanced". In the "Force Includes" line on the right, add the relative path to the header files. My "debug.h" file sits in the folder where the VS *.sln file is, so I used a handy built-in macro to define the path, like this:
$(SolutionDir)debug.h
We're not done yet! Move on to the next page to find out how to output the data!
You need to actually provide a call somewhere in your program to dump the memory leak data. Obviously, that should usually be done right at the end of the program. There apparently are ways of making it happen automatically on program termination, but being a stickler for D-structured programming, I just manually called it right at the end of the "WinMain" function. It's done using a single function call, like this:
_CrtDumpMemoryLeaks();
Now (in debug mode) you can compile and run the program (I recommend a full re-build, to make sure everything gets re-compiled with the debug settings). When the program terminates, bring up the "debug output" console, and you'll see a report of any memory leaks that occurred, their size, location, and the name and line of source code file where the allocation was originally made.
"Hang on! Something isn't right!"
Indeed, contrary to the documentation, the allocation calls are not traced automatically to your allocations... they are all traced back to that "crtdbg.h" file, where the allocation/de-allocation functions are customized for debugging. So what do we do now? Well the MSDN documentation offered some suggestions, so I tinkered for a while.
The good news is that I managed to get it to trace all the allocations correctly. The bad news is that it requires you to replace all your "new" commands with a macro. (You're not seriously using "malloc" for most C++ programming... are you???? :p).
Go back to that header file you created ("debug.h" in my case), and add the following lines:
#ifdef _DEBUG
#define DBG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__)
#else
#define DBG_NEW new
#endif
(Note: apparently you can replace "_NORMAL_BLOCK" with "_CLIENT_BLOCK" if you want the allocations to be of client block type... although I don't know the difference...)
Anyway, now comes the annoying bit. Go and replace all your "new" calls with "NEW_DBG". When in debug mode, they will get replaced by this handy call which correctly identifies the file and line number. When in release mode, they simply get replaced by a regular "new" call.
But why not just make a "new" macro?!
That's a good question. Why not just make our handy macro get invoked whenever you type "new", instead of needing to replace all our allocations with a nasty other macro (i.e. use "#define new ..." instead of "#define DBG_NEW ...". In some cases, that's entirely possible... but feel free to try it with this setup. I did, and I nearly drowned in error messages. Remember that we're including the "debug.h" header EVERYWHERE, so it does tend to get a little conflicted with some other stuff. (There may well be another way round it which I haven't found, of course...)
You can stop here if you like, but I'm still not done for today! Do you want to output the memory leak data to a file instead? Move on to the next page...
There are various means of outputting CRT stuff to different places, and a useful one is to a log file. (I always prefer to open up the memory log in a good text editor, so I can search it and so forth). It's not too complicated, but it's maybe not entirely intuitive either.
The first thing you need to do is to create/open an appropriate output file. Do that using the following lines, right at the top of your main function ("WinMain(..)" or whatever):
HANDLE hCrtLog;
hCrtLog = CreateFile(TEXT("crt.log"), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
That just creates a handle called 'hCrtLog', then uses it to create/open a file called "crt.log". Before you tell the CRT where to send error data, you need to check that the file was opened successful. If it was successful, then you want to re-direct CRT warnings and errors to file output, and you also need to specify which file to use. The following lines do all that:
if (hCrtLog != INVALID_HANDLE_VALUE)
{
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, hCrtLog );
_CrtSetReportFile( _CRT_ERROR, hCrtLog );
}
Last but not least, you need to close the file at the end of your program. Put the following bit of code just after your call to _CrtDumpMemoryLeaks()
if (hCrtLog != INVALID_HANDLE_VALUE)
CloseHandle(hCrtLog);
Finally... that's it. Compile and run your program in debug mode, and after you exit, you should see a "crt.log" file. (It might be alongside the executable file or alongside the VS project file). Open it up, and you'll see all your memory leak data. If you want to test it, just put a "new ..." commnd somewhere in your program, and don't delete the object afterwards. Check if the source file and line reported in the log file are correct.
This post ended up being a lot longer than I expected, but I found this stuff immmensely useful, and I hope someone else does too!