For example,
#include <My_Debug_New.h>
using namespace std;
int main()
{
int* p1 = new int;
int* p2 = new(nothrow) int; // note this!!!
}
Ideally, after running it in debug mode, owing to p1 and p2 are not
deleted, the output window of the IDE should report memory leaks with
source file names and actual line numbers.
Provided that the whole program doesn't use new(nothrow), I can
implement a memory leak detector as follows:
#if _DEBUG
void* operator new(size_t size, char* srcFileName, int nLineNum);
void* operator delete(void* p);
// ......
#define new new(__FILE__, __LINE__)
#endif
However, by using macro, new and new(nothrow) cannot be simultaneouly
supported. My question is: How to implement this feature that can
simultaneously support? Is this feasible?
Thanks in advance for any help.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
I can think of one way to record both new and new(std::nothrow)
allocations - although the solution is somewhat more elaborate. The
idea is to declare a "NewRecorder" class and then insert NewRecorder
temporaries into the source code every time new is called.
The first step in this approach would be to define the NewRecorder
class. NewRecorder's constructor is expected to be initialized with the
file name and line number in which the call to new appears in the
source file. The memory allocation itself would be recorded in
NewRecorder's operator<< method, at which point the source file, line
number and pointer value of the allocation have been collected. (In
example below, NewRecorder just sends that information to std::cout):
struct NewRecorder
{
NewRecorder(const char *file, int lineNo)
: mFile(file), mLineNo(lineNo)
{
}
template <class T>
T * operator<<(T* t) const
{
// send to std::cout as a demonstration
std::cout << mFile << ":" << mLineNo
<< " " << t << "\n";
// Record mFile, mLineNo and t here:
// ...
}
private:
const char *mFile;
const int mLineNo;
};
Next define new as a macro like this:
#define new NewRecorder(__FILE__,__LINE__) << new
Now lines of code that call new - such as the following
int* p1 = new int;
int* p2 = new(std::nothrow) int; // note this!!!
are transformed into:
int* p1 = NewRecorder("test.cc", 74) << new int;
int* p2 = NewRecorder("test.cc", 75) << new(std::nothrow) int;
after preprocessing. Thereby the source file, line number and pointer
value of both new and new(std::nothrow) calls can be recorded.
Greg
My feeling it is that there might not be good ways to tackle the
problem itself. There are workarounds. If you use GCC, it is possible
to display the file/line information without even including a special
header file. See
http://wyw.dcweb.cn/leakage.htm
(Seek the section `Special improvement with gcc/binutils' if you do not
want to read about the basics of overriding operator new. If you choose
to do so, do take care that you have handled exception and
multi-threading correctly, which are also discussed in this article.)
If not, you might consider not using new directly. Use NEW and
NEW_NOTHROW instead to ease redefinition for debugging. Theoretically
it is ugly; practically it works in real projects.
Best regards,
Yongwei
It would be fairly simple for the constructor of his NewRecorder
object to acquire a lock, and the destructor to release it.
> My feeling it is that there might not be good ways to tackle
> the problem itself.
There is, but it isn't particularly portable. You write the
code to do a stack walkback, and use it in operator new. Of
course, the code to do a stack walkback is extremely unportable;
my version for Sparc uses inline assembler, for example, and
every version I've ever written depends on undefined behavior.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Yes, a class_level_lock will do the trick. It would not be much work
for me to implement it in my debug_new, in a `relatively'
cross-platform way (well, with a threading abstraction layer really). I
have some doubts whether the performance is acceptable to serialize all
memory allocation operations, but, considering the system might already
serializes all memory operations, it looks good and acceptable.
Best regards,
Yongwei