memory leak detection of static class variables

Started by
5 comments, last by GameDev.net 17 years, 9 months ago
The issue is shown in the simple console program posted below.. The problem: some static objects not being destroyed in time for memory leak detection

#include <crtdbg.h>
#include <map>

class TestClass
{
static int i;
static std::map<int, int> tMap;
};

std::map<int, int> TestClass::i;
int TestClass::tMap = 4;


void main()
{
	_CrtDumpMemoryLeaks();
}

var "i" reports 0bytes leak var "tMap" reports 24bytes same holds true for namespaces and static vars I am assumeing the tMap destroys after main terminates... is this true? also is ther any other way to force it to terminate aside from allocating it on the heap?
Advertisement
This is very simple to explain:

_crtDumpMemoryLeaks() is called earlier as the object are destroyed, take this time chart:

1. static class { static my map; }
2. main procedure
3. crtDumpMemoryLeaks
4. exit main procedure
5. destroy objects

to make sure, make your class non-static and also remove the static predicate before your members, and you will get a plain class. then make it so:

1. /*static*/ class { /*static*/ my map; }
2. main procedure
3. myClass* pTest = new myClass;
4. do some basic stuff with your pTest to check that it works properly
5. delete pTest
6. _crtDumpMemoryLeaks
7. exit main procedure

As you can se, you will call crtDumpMemoryLeaks after the destruction of your objects. It will work for static members too, but you can not call _crtDumpMemoryLeaks for static members because they have not left the scope yet!
Quote:Original post by Samurai Jack
As you can se, you will call crtDumpMemoryLeaks after the destruction of your objects. It will work for static members too, but you can not call _crtDumpMemoryLeaks for static members because they have not left the scope yet!

Technically, this is not quite correct. In C and C++, the "static" keyword serves a double role: it can be used to modify the scope as well as the lifetime of a variable (which is not the same!).
The problem here is not the scope, but the lifetime of the static members.
While their scope is fixed by the class they are declared within, their lifetime is modified by the static keyword.
Static class members are being instaciated in no particular order (though some compiler-dependent assumption can be made). They are destroyed after the program leaves the main() function (in the reverse order they have been constructed).

You can actually observe this behaviour using a simple test program:
#include <iostream>#include <string>// "Foo" simply logs its creation and destruction.class Foo {   std::string name;public:   Foo( std::string const & name ) : name(name) {     std::cout << "Foo instance \"" << name << "\" created.\n";   }   ~Foo() {     std::cout << "Foo instance \"" << name << "\" destroyed.\n";   }};// define a global "Foo" instance - accessible from other modulesFoo global("global");// create a local Foo instance - accessible only within this source file (C-style)static Foo staticFoo("local (static)");namespace {    // create a local Foo instance - accessible only within this source file (C++ style)    Foo localFoo("local (anonymous namespace)");    // atexit handler, called on program shutdown    void report() {        std::cout << "atexit handler called\n";    }}// Same as "Foo" but contains a static member variableclass Bar {    // static Foo instance - only accessible by "Bar" instances    static Foo foo;    std::string name;public:    Bar( std::string const & name ) : name( name ) {        std::cout << "Bar instance \"" << name << "\" created.\n";    }    ~Bar() {        std::cout << "Bar instance \"" << name << "\" destroyed.\n";    }};// static member variable contained by "Bar"Foo Bar::foo("Bar::foo");// global "Bar" instance, also accessible by other modulesBar b("global");int main() {    atexit(report);    // define some variables within the function's scope    Foo a("in main a"), b("in main b"), c("in main c");    Bar d("in main");}

Observing the output of the compiled program reveals that the class variable defined within "Bar" will indeed be destroyed. It will also show that this happens only after even the atexit handler finished. This means there is no place where you can check for memory leaks with static class member variables, but that these variables will indeed be destroyed.

Hope that clears things up a bit,
Pat.


Yeah that pretty much what I thought... Thanks
Quote:Original post by darookie
This means there is no place where you can check for memory leaks with static class member variables, but that these variables will indeed be destroyed.

Hope that clears things up a bit,
Pat.


Not true, the OP will be delighted to hear :).

If you call _cexit() then that does everything exit() does (including clearing up all static allocations). THEN do the leak test, then exit application as usual.

PufferFish
Quote:Original post by Anonymous Poster
Quote:Original post by darookie
This means there is no place where you can check for memory leaks with static class member variables, but that these variables will indeed be destroyed.

Hope that clears things up a bit,
Pat.


Not true, the OP will be delighted to hear :).

If you call _cexit() then that does everything exit() does (including clearing up all static allocations). THEN do the leak test, then exit application as usual.

PufferFish

*cough*
Quote:
from MSDN
_cexit
Performs complete C library termination procedures and returns to caller, but does not terminate process.
[...]
When you call the _cexit or _c_exit functions, the destructors for any temporary or automatic objects that exist at the time of the call are not called.

Sorry, no cookie for you [smile].

Cheers,
Pat.


Quote:

Sorry, no cookie for you [smile].

Cheers,
Pat.


Darn. And I LIKE cookies :)

The _cexit method was the only way I was able to square up allocation snapshot at the start of main() against the condition before you hit the final return(). I should have checked the MSDN smallprint before posting, however.

This topic is closed to new replies.

Advertisement