Re: Should Singleton instance be destructed after its usage
First, a very interesting discussion about singleton can be found in Modern
C++ design, particulary on destruction.
<subramanian100in@yahoo.com> a ?crit dans le message
news:<246ce334-c03b-4a6a-8cd2-67f9eda073c7@a10g2000pri.googlegroups.com>...
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