Singleton class and static data members of the class type
Hi : )
Last night a had a really hard time trying to understand the singleton pattern for a class which has a data member, with the same type as the class itself:
Code:
class Singleton
{
public:
void printData() { cout << data << endl;}
private:
Singleton(): data(0) { /* other work */ }
Singleton( const Singleton &); // never defined
Singleton & operator=( const Singleton &); // never defined
~Singleton();
int data;
static Singleton singleton;
};
Ok, so, now I want to be able to use object singleton as a regular object - a want to have access to its public data members from outside the class scope. Let's just say that I prefer to use an object of type Singleton, rather than a pointer to a Singleton object.
This code, as it is compiles fine, but singleton(the static object) is never created ( i think..)
I suppose, as any other static data member, singleton must be defined exactly once outside the class body. How do I do that with a private constructor?
I suppose I should define a public static function that:
1. creates dynamically an object if there is no object created
2.returns a reference to it..
Basically my question is:
If i define only one constructor that is private, how can I initialize the class static member, which is an object of the same type as the class itself outside the class definition?
It's all very confusing...
Re: Singleton class and static data members of the class type
Perhaps it would be easier just to show you a simple example of a singleton. This is my logger that I use in all my games (some stuff removed for simplicity):
Logger.h:
Code:
class Logger
{
public:
static void Initialise(const boost_path& file_name);
static Logger& Get();
void Log(const std::string& str);
void Save_Log();
private:
static Logger instance;
static bool initialised;
boost_path file_name;
std::vector<std::string> buffer;
};
Logger.cpp (LOG is just a #define that is a shorter way to call Logger::Get().Log()):
Code:
Logger Logger::instance;
bool Logger::initialised = false;
void Logger::Initialise(const boost_path& file_name)
{
if(!initialised)
{
instance.file_name = file_name;
instance.time_info = NULL;
instance.raw_time = 0;
initialised = true;
LOG("Logger initialised.");
}
else
{
LOG("Warning: Logger already initialised.");
}
}
Logger& Logger::Get()
{
if(!initialised)
{
throw std::runtime_error("Logger not initialised.");
}
return instance;
}
void Logger::Log(const std::string& str)
{
buffer.push_back(str);
}
void Logger::Save_Log()
{
// Save the log to file_name.
}
You can initialise the singleton like so:
Code:
Logger::Initialise("folder/file.txt");
When you're done:
Code:
Logger::Get().Save_Log();
Hope that helps.
Re: Singleton class and static data members of the class type
Quote:
Originally Posted by
seventhirty
This code, as it is compiles fine, but singleton(the static object) is never created ( i think..)
If you define it in a cpp file, it is created when the program starts up, before main() is executed.
Quote:
I suppose, as any other static data member, singleton must be defined exactly once outside the class body. How do I do that with a private constructor?
Code:
#include "Singleton.h"
Singleton Singleton::singleton;
Quote:
I suppose I should define a public static function that:
1. creates dynamically an object if there is no object created
2.returns a reference to it..
That's a different design for a singleton. It has it's benefits (singleton object is not created if it is never called, multiple singletons can be dependend on each other during initialization), but it is also much harder to implement. A good implementation can be found in the Loki library.
With the design you have, you just need a static member function that will return a reference to the one-and-only object.
Quote:
If i define only one constructor that is private, how can I initialize the class static member, which is an object of the same type as the class itself outside the class definition?
The static object is defined within the scope of the Singleton class. Therefore, it has access to the private constructor.
Re: Singleton class and static data members of the class type
Quote:
Originally Posted by
seventhirty
Hi : )
Code:
class Singleton
{
public:
void printData() { cout << data << endl;}
private:
Singleton(): data(0) { /* other work */ }
Singleton( const Singleton &); // never defined
Singleton & operator=( const Singleton &); // never defined
~Singleton();
int data;
static Singleton singleton;
};
hmm I dont know, but how can there be any object of type Singleton? I see no way of calling the constructor.
Re: Singleton class and static data members of the class type
The static object "singleton" will of course be created; it's within the class namespace, so it has access to the private constructor.
However, it isn't very useful since it's also private. Typically in the singleton pattern, you'd either make the static instance public so that you can access it as Singleton::singleton, or else you'd write a public static function to get it, such as Singleton::getInstance().
The function approach is usually preferred since it makes it possible to "silently" change what type of singleton it is in the future without modifying any code that uses it.
Re: Singleton class and static data members of the class type
Thanks for the answers.
Lindley, if I use the second approach that you mention, the one with the function getInstance, does that mean that everytime the user of the class wants to use some function the class, he/she has to call getInstance() to obtain the static object( like Mybowlcut's logger class)?
And a design question: when making some application do I have to make every class, of which there is only one object throughout the whole program, a singleton ( cursor, mainMenu, InputSubsystem, Renderer.. all the modules, everything??) I mean, if I do that and use the getInstance() approach, isn't that going to make all the code unclear and complicated??
Re: Singleton class and static data members of the class type
Quote:
Originally Posted by
seventhirty
Thanks for the answers.
Lindley, if I use the second approach that you mention, the one with the function getInstance, does that mean that everytime the user of the class wants to use some function the class, he/she has to call getInstance() to obtain the static object( like Mybowlcut's logger class)?
Well, you can always store the result of getInstance() into a local pointer or reference if you want. Then you don't have to call it so many times.
Quote:
And a design question: when making some application do I have to make every class, of which there is only one object throughout the whole program, a singleton ( cursor, mainMenu, InputSubsystem, Renderer.. all the modules, everything??) I mean, if I do that and use the getInstance() approach, isn't that going to make all the code unclear and complicated??
That's a valid concern----singletons are only a slightly better alternative to global variables, after all.
I'd say, use a singleton if and only if (a) it logically makes sense for there to be only one of something, (b) you'll need to access that single object from many widely-distributed areas of the program, and (c) passing a pointer to the object around would make it a parameter of just about everything anyway.