Archived

This topic is now archived and is closed to further replies.

Zorodius

Problem enforcing a singleton - Part Deux

Recommended Posts

I want to make a Singleton class that has the singleton pattern enforced. I want to make it so that it is not possible to create multiple instances of the singleton. I''m using C++. The following code behaves strangely, and I would appreciate it if someone could explain why:
#include <iostream>
using namespace std;

class singleton
{
	protected:
		singleton() { };
		singleton(const singleton &) { };
		singleton & operator= (const singleton &) { return *this; };
};

class foo
{
	public:
		//foo() { }; 	// The program runs if this line is not commented out.

		singleton a, b, c;
};

int main(void)
{
	foo bar;
	cout << "Foobar!" << endl;
	return 0;
}
For brevity''s sake, the "singleton" here has no ability to maintain the single instance. But that''s not relevant, the weird thing here is that, if the foo class is declared with a constructor, the program will compile without error (under MetroWerks Codewarrior) despite the fact that it should not be possible to instantiate a class that contains singleton members. If the constructor in foo is commented out, the program does not compile, and generates an error for invalid use of a protected/private member. I''m hoping that someone more familiar with this sort of thing can explain what''s wrong here, and how to implement a proper singleton.

Share this post


Link to post
Share on other sites
quote:
If the constructor in foo is commented out, the program does not compile, and generates an error for invalid use of a protected/private member.


That is standard behavior. I do not understand why the foo constructor would make it compile, though. foo::foo () should be invoking singleton::singleton () implicitly for foo::a, foo::b, and foo::c. Sounds like a compiler bug to me.

quote:
I''m hoping that someone more familiar with this sort of thing can explain what''s wrong here, and how to implement a proper singleton.


That depends on what kind of singleton you need.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Maybe it could be a bug with the compiler. It could be optimizing out the singleton members since they are never used, before trying to construct them. The effect of having the default constructor could be having some weird interaction with this sort of thing.

Share this post


Link to post
Share on other sites
The problem is that the class singleton has no relationship whatsoever to class foo. That means, from class foo''s viewpoint, singleton cannot created, because the default ctor, copy ctor, and assignment operator are all protected, and not public.

It''s no compiler bug, just the semantics of the C++ language at work.

This is how I implement 90% of my singletons:


#include <cassert>

template<typename TypeT>
class Singleton
{
public:
Singleton()
{
assert(sInstance == 0);
sInstance = static_cast<TypeT*>(this);
}
~Singleton()
{
assert(sInstance != 0);
sInstance = 0;
}
static TypeT& GetInstance()
{
assert(sInstance != 0);
return *sInstance;
}
protected:
static TypeT* sInstance;
};

template<typename TypeT>
TypeT* Singleton<TypeT>::sInstance = 0;

Share this post


Link to post
Share on other sites
Try this....



class Singleton {
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
};

Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance() {
if(_instance == 0)
_instance = new Singleton();

return _instance;
}



This guarantees that you only access the singleton instance from the static public method instance.

So wherever you need an instance, just do this:


Singleton* mySingleton = Singleton::Instance();


Hope this helps

Share this post


Link to post
Share on other sites
OP, its a compiler bug.

gcc 2.95 gives errors both ways, which is how it should be expected.

Just add an assert(m_instance==NULL) equivalent in the constructor just to be sure that you don''t accidentally create more than one while using the broken compiler.

Share this post


Link to post
Share on other sites