Irrlicht Application Hub Class
Irrlicht Application Hub Class
Link - http://www.saigumi.net/pivot/entry.php?id=19
/*******************************************************************************
Hub by Frank Taylor(Pharoseer) and John Goewert(Saigumi)
This is a singleton-style class that creates one instance of the hub.
Instead of passing around variables from class to class, all
you need to do is get the instance of the hub.
The first time the Hub instances is gotten, it will create an Irrlicht
device. Consecutive getInstance() calls will return the Hub instance's
pointer.
Usage:
#include "hub.h"
Hub* my_hub = Hub::getInstance();
Do NOT pass "my_hub" to another class. Instead, just use the same code to get
the instance of the class.
Each of the public pieces are controlled by accessor functions, so be sure to
include the braces ().
Example:
irr::scene::IAnimatedMesh* mesh =
my_hub->irr_scenemgr()->getMesh("sydney.md2");
Also, you can add any other core classes that you need into the hub, not
just Irrlicht ones. This will save you having to pass around a bunch of
pointers and allow any piece of your application to access shared resources.
*******************************************************************************/
/*******************************************************************************
Hub by Frank Taylor(Pharoseer) and John Goewert(Saigumi)
This is a singleton-style class that creates one instance of the hub.
Instead of passing around variables from class to class, all
you need to do is get the instance of the hub.
The first time the Hub instances is gotten, it will create an Irrlicht
device. Consecutive getInstance() calls will return the Hub instance's
pointer.
Usage:
#include "hub.h"
Hub* my_hub = Hub::getInstance();
Do NOT pass "my_hub" to another class. Instead, just use the same code to get
the instance of the class.
Each of the public pieces are controlled by accessor functions, so be sure to
include the braces ().
Example:
irr::scene::IAnimatedMesh* mesh =
my_hub->irr_scenemgr()->getMesh("sydney.md2");
Also, you can add any other core classes that you need into the hub, not
just Irrlicht ones. This will save you having to pass around a bunch of
pointers and allow any piece of your application to access shared resources.
*******************************************************************************/
Crud, how do I do this again?
A singleton class is a great thing. Makes everything much more flexible.
Saigumi, one thing I noticed, already a while ago, in your implementation is that your (only) getInstance takes 7 parameters with default values. I was askin myself right away: isn't that adverse because those parameters get always pushed on the stack, even though they are omitted in the normal program flow? Then I forgot about it...
Now that I'm doing some profiling and analysis on assembler level (compare how certain C++ implementations compare to others) I remembered your Hub class and became curious.
I added another getInstance to your class that takes no parameters: getInstance2(void). Now in assembler these compare like this:
(Compiled with MSVC .NET under XP Pro)
Hub::getInstance() (original, 7 defaulted parameters)
Hub::getInstance2() (void param)
Quite some overhead. Using this often in tight loops might sum up.
Next step in optimizing would be declaring it inline (then there won't be even a call to getInstance).
Hub::getInstance2()->irr_driver()->getFPS() results in:
I've also done a comparison of (f32, f32, f32) vs. (core::vector3df) with some benchmarking that I will maybe post later in the other thread where this has been discussed.
I'm not sure if this is really the best place for optimizing, and it's prolly also not recommended to use getInstance in tight loops but it's fun and insightful anyhow.
Saigumi, one thing I noticed, already a while ago, in your implementation is that your (only) getInstance takes 7 parameters with default values. I was askin myself right away: isn't that adverse because those parameters get always pushed on the stack, even though they are omitted in the normal program flow? Then I forgot about it...
Now that I'm doing some profiling and analysis on assembler level (compare how certain C++ implementations compare to others) I remembered your Hub class and became curious.
I added another getInstance to your class that takes no parameters: getInstance2(void). Now in assembler these compare like this:
(Compiled with MSVC .NET under XP Pro)
Hub::getInstance() (original, 7 defaulted parameters)
Code: Select all
push 0
push 0
push 0
push 0
push 10h
lea ecx,[esp+30h]
push ecx
push 4
mov dword ptr [esp+38h],320h
mov dword ptr [esp+3Ch],258h
call Hub::getInstance (4010D0h)
Code: Select all
call Hub::getInstance2 (401170h)
Next step in optimizing would be declaring it inline (then there won't be even a call to getInstance).
Hub::getInstance2()->irr_driver()->getFPS() results in:
Code: Select all
mov edx,dword ptr [Hub::m_instance (40BA20h)]
mov ecx,dword ptr [edx+4]
mov esi,dword ptr [eax+4]
mov eax,dword ptr [ecx]
add esp,38h
call dword ptr [eax+98h]
I'm not sure if this is really the best place for optimizing, and it's prolly also not recommended to use getInstance in tight loops but it's fun and insightful anyhow.
It is like it is. And because it is like it is, things are like they are.
Optimization of code for reduced overhead and speed.
Inlining is a possibility, but the downfall is that it replicates the code as many times as you call it in your compiled binary. Speed vs. Size.
I've been flipping through two books right now:Efficient C++: Performance Programming Techniques, which is awesome for lots of tips in working out performance and a great guide for STL methods, and Joel On Software, which has more to do with project management, but has a great set of tips on optimizing as well.
Since getInstance would be called by every object needing to talk to the hub, it is definitely something to look at improving. On the downside, improving it for one type of usage can cause performance issues in another.
I see what you mean about the blank getInstance call though. Since I was just using default loading as a way to handle a call with no parameters, I didn't realize that the default parameters still get stacked as if they were passed in.
Inlining is a possibility, but the downfall is that it replicates the code as many times as you call it in your compiled binary. Speed vs. Size.
I've been flipping through two books right now:Efficient C++: Performance Programming Techniques, which is awesome for lots of tips in working out performance and a great guide for STL methods, and Joel On Software, which has more to do with project management, but has a great set of tips on optimizing as well.
Since getInstance would be called by every object needing to talk to the hub, it is definitely something to look at improving. On the downside, improving it for one type of usage can cause performance issues in another.
I see what you mean about the blank getInstance call though. Since I was just using default loading as a way to handle a call with no parameters, I didn't realize that the default parameters still get stacked as if they were passed in.
Crud, how do I do this again?
That depends. If you have a singleton tha contains a static instance variable:
And also:
Then presumably your singleton will get created when you first retrieve it:
If you have:
Then the singleton will get instantiated before main() is called.
At least that's my understanding.
Code: Select all
private:
static MySingleton* mInstance;
Code: Select all
public:
static MySingleton* GetInstance();
Code: Select all
MySingleton* MySingleton::GetInstance()
{
if (MySingleton::mInstance == NULL)
{
MySingleton::mInstance = new MySingleton();
}
return MySingleton::mInstance;
}
Code: Select all
private:
static MySingleton mInstance;
Code: Select all
public:
static MySingleton& GetInstance();
Code: Select all
MySingleton& MySingleton::GetInstance()
{
return MySingleton::mInstance;
}
yes, however you dont have a method to be sure when it will first be instanced. Someone else can come play with your code and add a call earlier than what you expected.
Furthermore, while you can assume it gets destroyed at the end of your application, you cant assume in what order with respect to other singletons (importantly: with respect to other systems it may be reliant on)
I dont mean to say this is neccesarily bad in your case. Just wanted to make sure you weighed the cost.
Furthermore, while you can assume it gets destroyed at the end of your application, you cant assume in what order with respect to other singletons (importantly: with respect to other systems it may be reliant on)
I dont mean to say this is neccesarily bad in your case. Just wanted to make sure you weighed the cost.
a screen cap is worth 0x100000 DWORDS
-
- Posts: 16
- Joined: Mon Apr 11, 2005 2:32 pm
- Location: LEEDS, England
- Contact:
Definitely. I used Singletons in my games for a couple of years and often found that their use encouraged laziness and spaghetti-code. It has taken me a year to 'break' the habit and get my code back to how it should be. If you're tempted to use a Singleton because of the convenience factor, please take some time to ensure that it is what you need and not just a 'quick hack' to do what you need. Your code can and will suffer if you misuse Singletons.keless wrote:Sai, dont forget the disadvantages of using a singleton:
* cannot be sure when it will be initiated
* cannot be sure when it will be destroyed
* cannot be sure who will use it