Jump to content
  • Advertisement
Sign in to follow this  

memory leak detection of static class variables

This topic is 4345 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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 modules
Foo 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 variable
class 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 modules
Bar 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.


Share this post


Link to post
Share on other sites
Guest 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

Share this post


Link to post
Share on other sites
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.


Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!