Should Singleton instance be destructed after its usage

S

subramanian100in

The following question is NOT a homework problem. I am asking it for
learning purpose only.

Suppose I have a Singleton class and I have created an instance of the
Singleton class. Now, after the usage of the Singleton instance,
should the instance be deleted ? If it should be deleted, which of the
following two versions of deleting the Singleton instance should be
preferred ?

Program version 1:
---------------------------
#include <cstdlib>
#include <iostream>
#include <string>
#include <stdexcept>

using namespace std;

template <typename T> class SingletonDestroyer
{
public:
SingletonDestroyer();
~SingletonDestroyer();
};

template <typename T> inline
SingletonDestroyer<T>::SingletonDestroyer()
{
}

template <typename T> inline
SingletonDestroyer<T>::~SingletonDestroyer()
{
cout << "SingletonDestroyer dtor called" << endl;

delete T::p;
T::p = 0;
}

class Singleton
{
public:
friend SingletonDestroyer<Singleton>::~SingletonDestroyer();
static Singleton* getInstance(void);
int value(void) const;
void value(int arg);

private:
Singleton();
Singleton(const Singleton& arg);
~Singleton();

static bool instanceCreated;
static Singleton* p;
int val;
};

bool Singleton::instanceCreated = false;
Singleton* Singleton::p = 0;

inline Singleton::Singleton()
{
}

Singleton* Singleton::getInstance(void)
{
if (p)
return p;

if (instanceCreated)
{
const string e("Singleton instance already created
"
"but later destroyed");
cout << "From Singleton::getInstance(): " << e
<< endl;
throw logic_error(e);
}

p = new Singleton();
instanceCreated = true;

return p;
}

inline int Singleton::value() const
{
return val;
}

inline void Singleton::value(int arg)
{
val = arg;
return;
}
inline Singleton::~Singleton()
{
cout << "Singleton dtor called" << endl;
}

int main()
{
// first block
{
SingletonDestroyer<Singleton> sd;
Singleton::getInstance()->value(100);
cout << Singleton::getInstance()->value() << endl;
}

try
{
SingletonDestroyer<Singleton> sd;
Singleton::getInstance()->value(200);
cout << Singleton::getInstance()->value() << endl;
}
catch (const logic_error& e)
{
cout << "logic_error exception thrown: " << e.what()
<< endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

Program version 2:
----------------------------
#include <cstdlib>
#include <iostream>
#include <string>
#include <stdexcept>

using namespace std;

class Singleton
{
public:
friend class SingletonDestroyer;
static Singleton* getInstance(void);
int value(void) const;
void value(int arg);

private:
Singleton();
Singleton(const Singleton& arg);
~Singleton();

static bool instanceCreated;
static Singleton* p;
int val;
};

bool Singleton::instanceCreated = false;
Singleton* Singleton::p = 0;

inline Singleton::Singleton()
{
}

Singleton* Singleton::getInstance(void)
{
if (p)
return p;

if (instanceCreated)
{
const string e("Singleton instance already created "
"but later destroyed");
cout << "From Singleton::getInstance(): " << e
<< endl;
throw logic_error(e);
}

p = new Singleton();
instanceCreated = true;

return p;
}

inline int Singleton::value() const
{
return val;
}

inline void Singleton::value(int arg)
{
val = arg;
return;
}

inline Singleton::~Singleton()
{
cout << "Singleton dtor called" << endl;
}

class SingletonDestroyer
{
public:
SingletonDestroyer();
~SingletonDestroyer();
};

inline SingletonDestroyer::SingletonDestroyer()
{
}

inline SingletonDestroyer::~SingletonDestroyer()
{
cout << "SingletonDestroyer dtor called" << endl;

delete Singleton::p;
Singleton::p = 0;
}

int main()
{
// first block
{
SingletonDestroyer sd;
Singleton::getInstance()->value(100);
cout << Singleton::getInstance()->value() << endl;
}

try
{
SingletonDestroyer sd;
Singleton::getInstance()->value(200);
cout << Singleton::getInstance()->value() << endl;
}
catch (const logic_error& e)
{
cout << "logic_error exception thrown: " << e.what()
<< endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

Kindly explain.

Thanks
V.Subramanian
 
E

Eric Pruneau

First, a very interesting discussion about singleton can be found in Modern
C++ design, particulary on destruction.

The following question is NOT a homework problem. I am asking it for
learning purpose only.

Suppose I have a Singleton class and I have created an instance of the
Singleton class. Now, after the usage of the Singleton instance,
should the instance be deleted ?
I don't see any reason why... Why just don't wait until program's shutdown
unless you really want the overhead of a construction/destruction everytime
you need to use it. I see a singleton as something that is created once and
destroyed at the end of the program. The description in Design Pattern is
simple: "Ensure a class only has one instance, and provide a global point of
access to it".

If it should be deleted, which of the
following two versions of deleting the Singleton instance should be
preferred ?

I think your design could have some problems, like a double destruction...

e.g.

int main()
{

{
SingletonDestroyer<Singleton> sd;
SingletonDestroyer<Singleton> sd2
Singleton::getInstance()->value(100);
cout << Singleton::getInstance()->value() << endl;
} // bang, delete is called 2 times

return 0;
}

Ok you can always check if T::p is not 0 before deleting it, but what if
there is more than one thread usign your singleton? ( you may want to check
the double-checked locking pattern on that). Anyways, if your are in a multi
threaded environement, your getInstance function needs some changes too!

But if you really want to use a SingletonDestroyer, I would use the second
option. You call the class SingletonDestroyer, so I guess it is used to
destroy a Singleton. But the template version can be used to destroy pretty
much anything. So if you have a class Widget having a static pointer p, you
can use SingletonDestroyer to destroy Widget::p (you gonna have to declare
that SingletonDestroyer destructor is a friend in the Widget class). So use
the second version, there is less typing with this one too!
Program version 1:
---------------------------
#include <cstdlib>
#include <iostream>
#include <string>
#include <stdexcept>

using namespace std;

template <typename T> class SingletonDestroyer
{
public:
SingletonDestroyer();
~SingletonDestroyer();
};

template <typename T> inline
SingletonDestroyer<T>::SingletonDestroyer()
{
}

template <typename T> inline
SingletonDestroyer<T>::~SingletonDestroyer()
{
cout << "SingletonDestroyer dtor called" << endl;

delete T::p;
T::p = 0;
}
class Singleton
{
public:
friend SingletonDestroyer<Singleton>::~SingletonDestroyer();
static Singleton* getInstance(void);
int value(void) const;
void value(int arg);

private:
Singleton();
Singleton(const Singleton& arg);
~Singleton();

static bool instanceCreated;
static Singleton* p;
int val;
};

bool Singleton::instanceCreated = false;
Singleton* Singleton::p = 0;

inline Singleton::Singleton()
{
}

Singleton* Singleton::getInstance(void)
{
if (p)
return p;

if (instanceCreated)
{
const string e("Singleton instance already created
"
"but later destroyed");
cout << "From Singleton::getInstance(): " << e
<< endl;
throw logic_error(e);
}

p = new Singleton();
instanceCreated = true;

return p;
}

So if I understant correctly, once you have created a singleton and
destroyed it, there is no way to create a new one...
inline int Singleton::value() const
{
return val;
}

inline void Singleton::value(int arg)
{
val = arg;
return;
}
inline Singleton::~Singleton()
{
cout << "Singleton dtor called" << endl;
}

int main()
{
// first block
{
SingletonDestroyer<Singleton> sd;
Singleton::getInstance()->value(100);
cout << Singleton::getInstance()->value() << endl;
}

try
{
SingletonDestroyer<Singleton> sd;
Singleton::getInstance()->value(200);
cout << Singleton::getInstance()->value() << endl;
}
catch (const logic_error& e)
{
cout << "logic_error exception thrown: " << e.what()
<< endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

Program version 2:
----------------------------
#include <cstdlib>
#include <iostream>
#include <string>
#include <stdexcept>

using namespace std;

class Singleton
{
public:
friend class SingletonDestroyer;
static Singleton* getInstance(void);
int value(void) const;
void value(int arg);

private:
Singleton();
Singleton(const Singleton& arg);
~Singleton();

static bool instanceCreated;
static Singleton* p;
int val;
};

bool Singleton::instanceCreated = false;
Singleton* Singleton::p = 0;

inline Singleton::Singleton()
{
}

Singleton* Singleton::getInstance(void)
{
if (p)
return p;

if (instanceCreated)
{
const string e("Singleton instance already created "
"but later destroyed");
cout << "From Singleton::getInstance(): " << e
<< endl;
throw logic_error(e);
}

p = new Singleton();
instanceCreated = true;

return p;
}

inline int Singleton::value() const
{
return val;
}

inline void Singleton::value(int arg)
{
val = arg;
return;
}

inline Singleton::~Singleton()
{
cout << "Singleton dtor called" << endl;
}

class SingletonDestroyer
{
public:
SingletonDestroyer();
~SingletonDestroyer();
};

inline SingletonDestroyer::SingletonDestroyer()
{
}

inline SingletonDestroyer::~SingletonDestroyer()
{
cout << "SingletonDestroyer dtor called" << endl;

delete Singleton::p;
Singleton::p = 0;
}

int main()
{
// first block
{
SingletonDestroyer sd;
Singleton::getInstance()->value(100);
cout << Singleton::getInstance()->value() << endl;
}

try
{
SingletonDestroyer sd;
Singleton::getInstance()->value(200);
cout << Singleton::getInstance()->value() << endl;
}
catch (const logic_error& e)
{
cout << "logic_error exception thrown: " << e.what()
<< endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

Kindly explain.

Thanks
V.Subramanian



Eric Pruneau
 
R

Robert Fendt

And thus spake "Eric Pruneau" <[email protected]>
Sat, 13 Mar 2010 22:39:30 -0500:

(Note: nindly shorten your quotation next time, thanks.)
Ok you can always check if T::p is not 0 before deleting it, but what if
there is more than one thread usign your singleton? ( you may want to check
the double-checked locking pattern on that). Anyways, if your are in a multi
threaded environement, your getInstance function needs some changes too!

The 0-check is superfluous, since "delete 0" is legal and
harmless. However, the multi-threading problem (essentially a
race condition) is valid. Problems with concurrent computing
aside, the simplest way to destroy a singleton is to just give
the class a static 'destroy()' function. The destroyer object can
function as a 'scope guard' or similar, but is a lot of code for
very little gain if any.

However, routinely deleting singleton objects kind of defeats
the purpose of having a singleton in the first place. Just leave
it initialised and let the runtime system destroy it at program
exit.

Regards,
Robert
 
R

Robert Fendt

Just nit-picking: the object is not destroyed (destructor is not called),
it just ceases to exist.

Okay, I was a bit sloppy in my wording. Register a clean-up
handler then (via atexit()) that destroys the singleton(s) at
program exit. Better? :-D

Regards,
Robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top