In article < >,
(Spur) wrote:
> Hi all,
>
> I implemented a memory allocation/deallocation class that logs all
> new/delete calls (overloaded) and remembers for each allocated
> block where it was allocated from (using a macro that passes __FILE__
> and __LINE__). On destruction, it reports all undeleted blocks
> (memory leaks).
>
> The class is implemented in a separate .h/.cpp pair, and should be
> linked to
> code when I want to use it (plus a #define should be set and the
> header should be included).
>
> It works nicely, except for one problem - global objects. There is
> one global instance of the logging class in the .cpp file, and it
> catches all memory leaks from inside main() just fine. It misbehaves
> with global objects - reporting many false alarms.
>
> I'm aware of the fact that the order of construction/destruction of
> global objects (in different files) is not specified by the standard.
> However, I still wonder whether it's possible to implement this
> somehow portably ? Non-portably (after all, checking for memory leaks
> on one platform should be enough, I think...) ?
>
> If not, it would be another good reason to never use globals B-)
I've coded similar tools:
http://home.twcny.rr.com/hinnant/MemoryManager/
The approach I took was to implement my global memory allocator with a
simplistic singleton pattern (a function local static accessbile via a
returned reference). This isn't perfect, but it tends to work well in a
wide variety of circumstances. When a global constructor fires (before
main), and tries to allocate some memory, it will trigger the
construction of the global memory allocator before its own constructor
completes. At program termination, leak checking is done in the
destructor of the global memory allocator. With luck your allocator's
destructor will run after there is any more legitimate heap activity
occurring.
Note that there are situations where this design fails, most notably if
a global constructor runs before the memory allocator gets constructed
and does not allocate memory at that time, but then allocates memory
later in its lifetime. Its destructor will run after the allocator's
destructor has run, and thus will be freeing memory to an already
destructed allocator which has already flagged that memory as leaked.
So it's not perfect, but it tends to work fairly well in practice. In a
problem situation you could have the global "preflight" the debugging
allocator by allocating some memory in its constructor even though it
didn't need to.
There may also be an implementation defined way of ordering your global
constructors. I used to use this technique with my debugging allocator.
However after using that technique for a few years I finally changed to
the local static design because it was less of a pain in the rear to use
for the type of code I needed to monitor.
-Howard