views:

195

answers:

4

Hi,

When I have a class containing static stuff, how can I free the memory at the end of the application the best way?

Foo.h

class GLUtesselator;

class Foo
{
private:
    static GLUtesselator *tess;
public:
    Foo();
    virtual ~Foo();
}

Foo.cpp

#include "Foo.h"

#include <GL/glu.h>

GLUtesselator *Foo::tess = gluNewTess(); // System call

Foo::Foo() {}
Foo::~Foo()
{
     // And of course I don't want to destruct it here,
     // because I'm going to use the tesselator in other instances of Foo
     // Otherwise:
     // gluDeleteTess(tess);
}

Are there better alternatives to making a method to remove static stuff and call it when the app terminates?
Or can I say: "Oh, whatever, the application is terminated. The OS will free the memory..." ?

Thanks

+1  A: 

Since it's static, there will only ever be one instance. Unless this GLUtesselator is really huge, I doubt you will ever need to free it yourself.

like you said, "Oh, whatever, the application is terminated. The OS will free the memory..."

Bwmat
+6  A: 

Simple. Don't make the static member a pointer.
Then it will be correctly constructed and destructed.

Foo.h

#include <GL/glu.h>

class Foo
{
    private:
        static GLUtesselator  tess;
    public:
                 Foo();
        virtual ~Foo();
};

Foo.cpp

// 
GLUtesselator  Foo::tess;

If you have to use the gluNewTess() and gluDeleteTess() then you can use a shared pointer. I don't have a compiler so the exact usage may not be absolutely correct. But the shared_ptr does have this ability.

Foo.h

#include <GL/glu.h>

typedef std::shared_ptr<GLUtesselator,void (*)(GLUtesselator*)> AutoGluTess;
class Foo
{
    private:
        static AutoGluTess  tess;
    public:
                 Foo();
        virtual ~Foo();
};

Foo.cpp

// 
AutoGluTess    Foo::tess(gluNewTess(), &gluDeleteTess);
Martin York
I think the code above does exactly what you want. The only possible downside is the extra header dependencies.
ShaderOp
@Martin: Indeed! Sorry, I didn't see the static keyword!
Martijn Courteaux
@Martin: using shared_pointer it's possible NOT to include GL/glu.h, also the deleter can be supplied in the .cpp file and does not impact the shared_ptr type (at least... with boost implementation, it would be a regression if the std version suffered from this flow).
Matthieu M.
+3  A: 

You don't need to destroy it. All operating systems I know will correctly free the memory and release any resources held by the object on application termination (Note: the destructor will not be called automatically, but the resources will be freed).

If you really want to destroy it though, either

  1. Don't use a pointer as Martin York describes,
  2. Or (if you need a pointer), use an auto_ptr or tr1::unique_ptr so that the pointee is automatically deleted when it goes out of scope (which is at the end of the application for static variables).
Peter Alexander
I really think this is terrible advice. Not every resource is freed, and it's awful practice to get in to. "Leaks? Who gives a..." Fix the code!
GMan
I agree, which is why I described how to destroy it properly. Please don't exaggerate by extrapolating my advice to ignoring memory leaks.
Peter Alexander
"You don't need to destroy it." and "If you *really* want to destroy it though" doesn't sound like "you should fix the code/leaking is bad" to me.
GMan
I'm trying -- and failing -- to see what kind of leak you could possibly have with a static variable on program exit. Which operating system doesn't reclaim ALL of the resources used by a process when the process terminates?
JUST MY correct OPINION
@JUST, it will produce false positives on valgrind and friends even if it's reclaimed by the OS eventually.
bdonlan
@bdonlan: Really? Bear in mind that the static variable *lives to the end of the application anyway*, so it never actually leaks, no matter what way you look at it.
Peter Alexander
Not all memory can be reclaimed by all OSs. The global COM heap is an excellent example.
DeadMG
@Peter Alexander: I can see how valgrind would get confused if you have a static pointer to dynamically-created objects. This sounds, however, more like a limitation of valgrind than it sounds like a problem with letting the OS contend with things. @DeadMG: So if you're using the global COM heap you've got a bit more work to do than if you're using plain old C++ objects. In most C++ programs, however, under all but the pathological cases of platform limitations, it's perfectly OK to leave a program without manually releasing static resources.
JUST MY correct OPINION
+2  A: 

for global static variables:

CFoo* pFoo= NULL;

void DoneFoo()
{
    delete pFoo;
}

void Init()
{
    pFoo= new CFoo();
    atexit(DoneFoo);
}

or:

class CFoo
{
     ......
};

#define NewFoo(F_name)                                                             \
    CFoo* F_name##Init();                                                          \
    void  F_name##Done();                                                          \
    CFoo* F_name= F_name##Init();                                                  \
    CFoo* F_name##Init()  { CFoo* F= new CFoo(); atexit(F_name##Done); return F; } \
    void  F_name##Done()  { delete F_name; }    

NewFoo(F1);

for member static variables:

class CFoo
{
    static int* pKuku;
    static void DoneKuku() { delete pKuku;                     }
    static int* InitKuku() { atexit(DoneKuku); return new int; }
public:
};

int* CFoo::pKuku= CFoo::InitKuku();

I don't think it is a good idea to let the OS free memory automatically, because you'll have memory leaks. When you have 'legitimate' memory leaks - it will be harder to notice 'illegitimate' ones, so you should strive to having no memory leaks at all.

Lior Kogan
+1: Because of `atexit()`! Something new for me.
Martijn Courteaux
+1: I also think that letting the OS reclaim memory is not the way to go, for once it clutters the output of memory leak detection tools :/
Matthieu M.