Reputation: 2440
So this is a homework project first and foremost. My whole program is working, it was an intermediate/advancedintro project to deal with dynamic memory allocation. I can't figure out how to display the line numbers with the normal output. I've attempted to look at the other questions on stack about this topic but I cannot seem to figure out a reason that helps me. Any suggestions to how to make the line number appear?
Here is my "LeakWatcher.cpp"
#ifndef IMWATCHINGYOULEAK
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{ return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); }
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard
And my main()
int main()
{
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
try
{
Directory().Run();
}
catch ( ... )
{
cout << "Uncaught Exception" << endl;
}
_CrtDumpMemoryLeaks();
return 0;
}
Upvotes: 0
Views: 798
Reputation: 47603
Something that did occur to me based on your code is this. You say you placed all the debug macros into LeakWatcher.cpp
and not LeakWatcher.h
. I suspect this is your issue.
Create LeakWatcher.h
with everything you currently have in your LeakWatcher.cpp
. You don't need LeakWatcher.cpp
so you should be able to remove it. Now use #include "LeakWatcher.h"
at the top of all of your .cpp
files. So it would look something like the following.
File LeakWatcher.h
#ifndef IMWATCHINGYOULEAK
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{ return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); }
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard
Then in a file like test.cpp you can do this (similar to your test code):
#include "LeakWatcher.h"
int main()
{
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
new int[40]; // This should be a memory leak
_CrtDumpMemoryLeaks(); // This should dump with line numbers and file names
return 0;
}
Of course this will only work if you are building debug
versions of your project.
To get some other insights into overriding these heap routines, I found this MSDN Article valuable.
Upvotes: 1
Reputation: 118445
I presume you're asking about the actual algorithm of keeping track of memory that's been allocated but not released.
The typical approach of keeping track of where your memory allocation requests came from, for the purposes of producing diagnostic output is as follows:
Say you want to track the caller requested n_bytes
worth of memory.
Allocate n_bytes
+sizeof(const char *)+sizeof(int).
Store FILE and LINE in the first part of the allocated memory, and return the rest of the allocated memory as supposedly what's been allocated.
Something like this:
struct hdr {
const char *file;
int line;
};
void *my_allocation_request(const char *file, int line, size_t nbytes)
{
struct hdr *p=(struct hdr *)malloc(nbytes+sizeof(hdr));
p->file=file;
p->line=line;
// Here be dragons
return (void *)(p+1);
}
(presumably, your new
operator gets punted here).
Similar, when something wants to deallocate a memory block
void my_deallocation_request(char *p)
{
struct hdr *h=reinterpret_cast<hdr *>(p+1);
// Here be dragons
free(h);
}
Before this can be a final solution, you'll also need to write a bit more code that goes into the "Here be dragons" part, and I think you could probably figure it out yourself:
A) Take each newly allocated memory and put it on a list of some kind (the first location of dragons).
B) Remove the allocated memory from a list of some kind (the second location of dragons).
Then, at the end of your program, you can go through anything that's left on the list. That's going to be your leaked memory, and you'll have the file and the line number where it was allocated from.
Note that you'll probably want to implement the linked list of unreleased memory blocks manually. Using some standard container will probably result in an infinite loop, due to container's very reasonable expectation of being able to allocate memory for its own use, which will loop back into your own new/delete intercepts, which will ask the container to allocate more memory, which will loop back into your own new/delete intercepts, etc...
There might be some implementation-specific issues here regarding alignment of allocated memory, but it's unlikely, and this hair-splitting can probably be ignored, for now.
Upvotes: 0