Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I would recommend you to use <code>valgrind</code> for linux. It will catch not freed memory, among other bugs like writing to unallocated memory. Another option is mudflap, which tells you about not freed memory too. Use <code>-fmudflap -lmudflap</code> options with gcc, then start your program with <code>MUDFLAP_OPTIONS=-print-leaks ./my_program</code>. </p> <p>Here's some very simple code. It's not suitable for sophisticated tracking, but intended to show you how you would do it in principle, if you were to implement it yourself. Something like this (left out stuff calling the registered new_handler and other details).</p> <pre><code>template&lt;typename T&gt; struct track_alloc : std::allocator&lt;T&gt; { typedef typename std::allocator&lt;T&gt;::pointer pointer; typedef typename std::allocator&lt;T&gt;::size_type size_type; template&lt;typename U&gt; struct rebind { typedef track_alloc&lt;U&gt; other; }; track_alloc() {} template&lt;typename U&gt; track_alloc(track_alloc&lt;U&gt; const&amp; u) :std::allocator&lt;T&gt;(u) {} pointer allocate(size_type size, std::allocator&lt;void&gt;::const_pointer = 0) { void * p = std::malloc(size * sizeof(T)); if(p == 0) { throw std::bad_alloc(); } return static_cast&lt;pointer&gt;(p); } void deallocate(pointer p, size_type) { std::free(p); } }; typedef std::map&lt; void*, std::size_t, std::less&lt;void*&gt;, track_alloc&lt; std::pair&lt;void* const, std::size_t&gt; &gt; &gt; track_type; struct track_printer { track_type * track; track_printer(track_type * track):track(track) {} ~track_printer() { track_type::const_iterator it = track-&gt;begin(); while(it != track-&gt;end()) { std::cerr &lt;&lt; "TRACK: leaked at " &lt;&lt; it-&gt;first &lt;&lt; ", " &lt;&lt; it-&gt;second &lt;&lt; " bytes\n"; ++it; } } }; track_type * get_map() { // don't use normal new to avoid infinite recursion. static track_type * track = new (std::malloc(sizeof *track)) track_type; static track_printer printer(track); return track; } void * operator new(std::size_t size) throw(std::bad_alloc) { // we are required to return non-null void * mem = std::malloc(size == 0 ? 1 : size); if(mem == 0) { throw std::bad_alloc(); } (*get_map())[mem] = size; return mem; } void operator delete(void * mem) throw() { if(get_map()-&gt;erase(mem) == 0) { // this indicates a serious bug std::cerr &lt;&lt; "bug: memory at " &lt;&lt; mem &lt;&lt; " wasn't allocated by us\n"; } std::free(mem); } int main() { std::string *s = new std::string; // will print something like: TRACK: leaked at 0x9564008, 4 bytes } </code></pre> <p>We have to use our own allocator for our map, because the standard one will use our overridden operator new, which would result in an infinite recursion. </p> <p>Make sure if you override operator new, you use the map to register your allocations. Deleting memory allocated by placement forms of new will use that delete operator too, so it can become tricky if some code you don't know has overloaded operator new not using your map, because operator delete will tell you that it wasn't allocated and use <code>std::free</code> to free the memory. </p> <p>Also note, as <em>Pax</em> pointed out for his solution too, this will only show leaks that are caused by code using our own defined operator new/delete. So if you want to use them, put their declaration in a header, and include it in all files that should be watched. </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload