Advertisement

Singleton destruction?

Started by August 05, 2001 09:16 PM
5 comments, last by kill 23 years, 6 months ago
I have a singleton class. Something like that:
  
class CMyClass
{
public:
    static CMyClass* GetMyClass();
private:
    CMyClass();
    ~CMyClass();
    static CMyClass *m_pMyClass;
};

CMyClass *CMyClass::m_pMyClass = NULL;
CMyClass* CMyClass::GetMyClass()
{
    if(m_pMyClass == NULL)
        m_pMyClass = new CMyClass();
    return m_pMyClass;
}
  
This code works very well, except for one problem I am having. As you can see the destructor is private because I don''t want anyone to delete the instance of the class. However, the destructor has some crucial code in it, and I want to make sure that when the application exits, the destructor will be executed. Is there a way I can define a static function that''s guranteed to be called when the application quits, so I can delete the instance from that function? Or is there another way? Any help is greatly appreciated.
I don''t know if there''s a way to guarantee the function is called, but have a static function called CMyClass::CleanUp or something that deletes m_pMyClass.

I''d suggest an auto_ptr, which is exactly what you could use, only it requires public access to your destructor (correct me if I''m wrong someone)
Advertisement
kill, since your singleton is instantiated on first use, you DO NOT need to use a pointer. You can simply do this :

  class myClass{public:myClass* GetMyClass(){    static myClass obj;    return &obj}//other functions};  


This will give you 2 things :

1. Object is instantiated on first call of GetMyClass.
2. You are sure that the destructor will be called. It will be called somethime after main returned. You don''t know when, but It will.



I had exactly this same problem recently. And it''s interesting that the Design Patterns book doesn''t have anything to say on the problem of ensuring that Singletons get destroyed. My ''quick fix'' was to make a static Free() function, that in your case would simply be "delete m_pMyClass;" This will be safe even if you never created an instance of the singleton. Of course, you need to remember to put this in your program''s clean up code which, to me, seems to defeat the object a little. But, it works, and it''s safe.
Aha! Very cunning, Gorg. Yes, that works. You learn a new thing every day. Of course, it's not much good to me in my case because I need to ensure that the singleton is destroyed before the rest of the application. No big deal though.

Edited by - Kylotan on August 5, 2001 12:07:17 AM
Big B''s correct, you could use an auto_ptr if you''re willing to make the destructor public:


#include

class CMyClass
{
public:
~CMyClass();
static CMyClass* GetMyClass();
private:
CMyClass();
};
CMyClass* CMyClass::GetMyClass()
{
static std::auto_ptr s_pMyClass(new CMyClass());
return s_pMyClass.get();
}


Alternatively, you could use a static instance and return a reference to it:

class CMyClass
{
public:
~CMyClass();
static CMyClass& GetMyClass();
private:
CMyClass();
static CMyClass m_MyClass;
};
CMyClass CMyClass::m_MyClass;
CMyClass& CMyClass::GetMyClass()
{
return m_MyClass;
}

Those are the simplest solutions I can think of.

- Matt
Advertisement
A solution I read about on a website (I don''t recall which) created a static "janitor" inside the singleton that deleted the object in question in its destructor. Since the janitor is static it''s destructor will be called at program termination and thus it will delete the singleton''s object properly without explicit instructions from the programmer. Below is an example of a janitor assuming you have a proper base class to work with. If you don''t you can create a specific janitor or possibly use a void* and RTTI--I don''t know if the latter will work, I''ve never used RTTI.

class Janitor {
public:
Janitor(Object* t) {garbage = t;}
~Janitor() {if (t != 0) delete garbage;}
void set(Object* t) const {if (t == 0) {delete garbage; garbage = 0;} else garbage = t;}

private:
Object* garbage;
};

Then your class looks like this:

class CMyClass
{
public:
static CMyClass* GetMyClass();

private:
CMyClass();
virtual ~CMyClass(); // MUST be virtual unless a specific janitor is used
static CMyClass *m_pMyClass;
static Janitor habib; // everyone''s favorite janitor
};

CMyClass* CMyClass::m_pMyClass = 0;
Janitor CMyClass::habib(0);

CMyClass* CMyClass::GetMyClass()
{
if(m_pMyClass == 0)
{
m_pMyClass = new CMyClass();
habib.set(m_pMyClass);
}

return m_pMyClass;
}

So as you can see when the static section of CMyClass is being cleared up the destructor for habib will be called and hence the destructor for the singleton object will be called.

This topic is closed to new replies.

Advertisement