Re: Re-usable singleton class that can construct pointers to objects with non-trivial constructors
On 14 Srp, 19:44, Eric Lilja <mindcoo...@gmail.com> wrote:
As the topic says, I wanted to make a re-usable singleton class that
could create pointers to objects with non-trivial constructors. I came
up with this:
#ifndef SINGLETON_HPP
#define SINGLETON_HPP
template<typename T>
struct DefaultCreatorFunctor
{
T * operator()() const { return new T; }
};
template<typename T>
struct ValueCreatorFunctor
{
ValueCreatorFunctor(const T& val) : val_(val) {}
T * operator()() const { return new T(val_); }
private:
T val_;
};
/* Users can add more functors for more elaborate types. */
template <typename T1, typename T2>
class Singleton
{
public:
static T1 * get_instance(const T2& creator)
{
if (!obj)
{
obj = creator();
}
return obj;
}
private:
Singleton() {}
static T1 *obj;
};
template <typename T1, typename T2>
T1 * Singleton<T1, T2>::obj = 0;
#endif /* #ifndef SINGLETON_HPP */
As you can see I've provided to default functor, one for default-
constructing and one for objects with a constructor that takes a
single value.
I've made the following test program:
#include <iostream>
#include <string>
#include "singleton.hpp"
using namespace std;
int
main()
{
int *n = Singleton<int, ValueCreatorFunctor<int>
::get_instance(ValueCreatorFunctor<int>(4711));
cout << *n << endl;
delete n;
string *s = Singleton<string, DefaultCreatorFunctor<string>
::get_instance(DefaultCreatorFunctor<string>());
cout << *s << endl;
delete s;
return 0;
}
it seems to work but somehow I don't feel very satisfied. The syntax
for obtaining an instance is not elegant and if you want to a more
elaborate class to be handled as a singleton, you will have to write
your own functor (basically a ValueCreatorFunctor with additional
parameters). It was however a good exercise in templates and functors
for me and for that I'm glad.
Also I was thinking about ways in which I could make the singleton
delete its pointer when the program exits, so the user doesn't have to
worry about that (and risk double deletes).
As always, I would like comments from you. :-)
- Eric
Hi.
I have few comments:
1. Method get_instance should be named create_instance, because it
always creates new instance.
2. To delete singleton object at the end of program, look at the
atexit function in <cstdlib>
3. If you need variable parameters, you can give yourself a limit,
let's say 10 parameters as maximum. Then you can write such function
this way:
template<typename T>
class SomeClass
{
public:
// .. Some stuff ...
T* Func() { return new T(); }
template<P1 p1>
T* Func(P1 p1) { return new T(p1); }
template<typename P1 p1, typename P2 p2>
T* Func(P1 p1, P2 p2) { return new T(p1, p2); }
template<typename P1 p1, typename P2 p2, typename P3 p3>
T* Func(P1 p1, P2 p2, P3 p3) { return new T(p1, p2, p3); }
// etc.
};
Only used member functions will be generated, so you do not have to
worry about size. If you will try function with wrong parameters,
you'll get compilation error.