Skip to main content
GameDev.net gamedev.net
🔒 Locked

C++ singleton classes

Started by FBOD May 25, 2006 at 11:19 PM 7 replies 1.1k views
Original Post
FBOD
FBOD
I'm learning C++ and I'm having trouble understanding singleton classes fully. First of all why does it need its instance pointer declared globaly outside of the class before it can be used? example: SingletonExample *SingletonExample::PtrInstance; What does declaring things like this outside the class do? Is it just another form of prototyping? WHY? Second why does it need a normal instance of it created before a pointer to be initialized to it? example: //inside main proc. SingletonExample SingletonInstance; SingletonExample *PtrToSingleton; PtrToSingleton = SingletonExample::GetSingleton(); Wouldn't initializing the pointer create an instance in memory? Or does it need that instance so the constructor can initialize the class by returning itself to it's own pointer? I think I just answered my own question :p But I still need an answer to the first question.
pulpfist
pulpfist
Quote:

SingletonExample *SingletonExample::PtrInstance;

This line is the same as
SingletonExample *SingletonExample::PtrInstance = 0;,
since static member variables in C++ is initialized to zero by default.

This is how static members is initialized in C++.
If you think about it, the alternative is to initialize it in the contructor of the class. If we did that, the static variable would be initalized every time a new object was created.

More info here

Im not sure I understand the last question.
Initializing a pointer will not execute any contructors, and will not create any instances.
There exist only one instance in your example, called SingletonInstance.
Sneftel
Sneftel
Quote:
Original post by FBOD
SingletonExample *SingletonExample::PtrInstance;

What does declaring things like this outside the class do? Is it just another form of prototyping? WHY?

It's not prototyping. That line, in that source file, is the point at which the compiler actually sets aside an area of memory to hold the static variable. The line in the class definition tells the compiler that it'll be there somewhere. But since there needs to be exactly one place where it actually is, exactly one source file needs to actually define the variable.
JohnBolton
JohnBolton
Quote:
Original post by FBOD
First of all why does it need its instance pointer declared globaly outside of the class before it can be used? What does declaring things like this outside the class do? Is it just another form of prototyping? WHY?

A static member variable is declared in the class declaration, but it must also be defined somewhere. That is how the language works. There are two important words here: "defined" and "declared". Basically, a declaration describes a type, describes a variable's type, or describes a function's signature ("prototype"). A definition creates an instance of a variable or implements the body of a function.

Quote:
Original post by FBOD
Second why does it need a normal instance of it created before a pointer to be initialized to it? example:

//inside main proc.
SingletonExample SingletonInstance;
SingletonExample *PtrToSingleton;

PtrToSingleton = SingletonExample::GetSingleton();

A singleton has a single instance. How that instance is created depends on how the singleton is implemented. Different implementations do it differently. But your example doesn't look right. Usually, the instance of the singleton is created by the GetSingleton() function.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
FBOD
FBOD
Ok I've found in my book where it talks about declaring static data members in the global namespace :) For the last question how can the instance be created with the GetSingleton() function? The example I'm given looks like this:

SingletonExample *SingletonExample::GetSingleton()
{
assert(PtrInstance); //PtrInstance is the static member talked about before
return PtrInstance;
}

Here is how PtrInstance is created in my constructor:
SingletonExample::SingletonExample()
{
assert(!PtrInstance);
PtrInstance = this;
}

If I remove the line from my code where the first instance is declared in main,

SingletonExample SingletonInstance;

then I get an error where assert checks PtrInstance in my GetSingleton() function. (Note: the program links and runs, but quits when it gets to this assert)
pulpfist
pulpfist
Quote:

Ok I've found in my book where it talks about declaring static data members in the global namespace :) For the last question how can the instance be created with the GetSingleton() function? The example I'm given looks like this:

SingletonExample *SingletonExample::GetSingleton()
{
assert(PtrInstance); //PtrInstance is the static member talked about before
return PtrInstance;
}

Here is how PtrInstance is created in my constructor:
SingletonExample::SingletonExample()
{
assert(!PtrInstance);
PtrInstance = this;
}

If I remove the line from my code where the first instance is declared in main,

SingletonExample SingletonInstance;

then I get an error where assert checks PtrInstance in my GetSingleton() function. (Note: the program links and runs, but quits when it gets to this assert)


Thats right.
The first object created is SingletonInstance.
When the contructor for that object is run, the PtrInstance equals zero, so the assert is ok, and the PtrInstance is pointed to "this" object (assert will abort the program if the expression inside it is false)

Note that the object is not created with the GetInstance function. It is created by you in the line
SingletonExample SingletonInstance;

If you try to create another object of type SingletonExample, the PtrInstance will not equal zero, and the assert in the contructor will abort the program.

The rule that the author is trying to enforce here is that you must create exactly one SingletonExample object for things to work properly.

A cleaner way to do it (and more common I think) is to write the GetSingleton function like this:
SingletonExample& SingletonExample::GetSingleton(){    static SingletonExample instance;    return instance;}

Nothing more, nothing less.
In this case the instance is created in the GetSingleton function (the first time it is called), and a reference, rather than a pointer is returned.

Also note that functions returning or dealing with static variables should be static themself. (There might be a few exception to this rule though)
So in other words, make sure the GetSingleton function is declared static.
FBOD
FBOD
I get it (I think). Because the instance created in your GetSingleton() is static, then no matter how many times I call GetSingleton() it will always use that variable, but since this is a static variable inside a function in the class do I need to define it globaly like I would with other static variables in the class? And yes I am making GetSingleton() a static member, thanks for pointing that out. That's why I can call GetSingleton() without an instance handle (says my book). And one more thing, using the method you gave me my constructor and the need for a globaly declared pointer would stay the same wouldn't they? Your GetSingleton() example just encapsulates the creation of an instance and the assigning of a pointer(or reference) to that instance into the GetSingleton() method. This works because the constructor is called automatically every time an instance is created (like in GetSingleton()). Do I have it all right?

Sorry if my questions are a pain. My book I'm using is one of those "All in one" books so it's kind of vague on some details :(

[Edited by - FBOD on May 27, 2006 11:21:48 PM]
pulpfist
pulpfist
As far as I know, static variables declared inside a function scope is kinda different from static class member variables. You dont need to define them anywhere else, and they only exist in the scope of the function.
No matter if it is a class member function or global function.
JohnBolton
JohnBolton
The static keyword does different things depending where it is used:
  1. static in a class definition (static member variable) -- the variable has a single instance shared by all instances of the class. The variable must also be defined somewhere (without static).
  2. static in a function (static function variable) -- the variable is created (and initialized) the first time the function is executed and remains around forever.
  3. static outside of a function or a class (static variable) -- the variable is accessible only in the file it is declared in and only after its declaration. This usage is deprecated in favor of using an anonymous namespace.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.