How to Acess a singleton from everywhere?

Started by
36 comments, last by Jay Pascua 9 years, 1 month ago

Hi, I'm new in the singleton world, I used to think that i was using singletons, but really i was using static variables instead tongue.png

example: I have Core.h:


#pragma once


#define WIN32_LEAN_AND_MEAN




const bool FULL_SCREEN = false;
const bool VSYNC_ENABLED = true;
const float SCREEN_DEPTH = 1000.0f;
const float SCREEN_NEAR = 0.1f;


#include "Renderer.h"
#include "inputclass.h"
#include "Camera.h"
#include "ObjectsManager.h"
//
#include "MeshRenderer.h"
#include "ColorMaterial.h"
#include "ColorShader.h"
//
#include "Game.h"



class Core
{
private:
	//Singleton
	static Core* m_Core;
	Core();
	Core(const Core&);
	~Core();
	



	bool Frame(bool first_frame);
	bool InitializeWindows(int&, int&);
	void ShutdownWindows();


	LPCWSTR m_applicationName;
	HINSTANCE m_hinstance;
	HWND m_hwnd;

	//Singletons
	Renderer* m_renderer;
	ObjectsManager*	m_Objmanager;
	InputClass* m_Input;	
	Camera* m_Camera;
	Game* m_game;
	//test
	//D3DClass* d3d;
	//ID3D11Device* d3d_Device;
	//ID3D11DeviceContext* d3d_DeviceContext;

	ColorShader* color_shader;

public:
	//Singleton
	static Core* GetInstance()
	{
		m_Core = new Core;
		return m_Core;
	}

	//Core();
	

	
	bool Initialize();
	void Shutdown();
	void Run();

	//get window handler
	
	

	LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);

	//singletons 
	inline HWND* GetHwnd()	{	return &m_hwnd;	}
	inline Renderer* GetRenderer()	{	return m_renderer;	}	
	inline ObjectsManager* GetObjManager()	{	return m_Objmanager;	}
	inline InputClass* GetInput()	{	return m_Input;	}
	inline Camera* GetCamera() { return m_Camera; }
	inline Game* GetGame()	{	return m_game;	}
	inline ColorShader* GetColorShader()	{ return color_shader; }




};


static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);





in Core.cpp I have this line:


Core* Core::m_Core = 0;

I have the previous line in Renderer.cpp , Inputclass.cpp , .. and so on, in all my singletons classes.

So, in the cpp (where almost everything happens) I have initialize every singleton, Here is and example with renderer singleton inside Core::Initialize():


m_renderer = Renderer::GetInstance();
	if (!m_renderer)return false;		
	
	result = m_renderer->Initialize(screenWidth, screenHeight, m_hwnd, SCREEN_DEPTH, SCREEN_NEAR);
	if (!result)
	{		
		return false;
	}

in main.cpp:


#include "Core.h"


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
	
	bool result;
	
	//Core Singleton 
	Core* m_Core = Core::GetInstance();     
	

	// Initialize and run the system object.
	result = Core::GetInstance()->Initialize(); 
	if (!result) return -1;

//.....
}

Questions:

1 - Should I call m_renderer every time i want my renderer singleton (same with others) or should I call Renderer::GetInstance() ??

2 - How can I initialize a singleton that depends of another singleton? (for example first I have to initialize d3d, then initialize
renderer)

3 - in main.cpp should I define a "m_Core" or use directly GetInstance()? what is the difference?

4 - Do I need to pass a singleton to a function? for example (inside core.cpp):


bool Core::Frame()
{
	bool result;
	
//...
//some code
//...
	
	result = m_renderer->Frame(m_Camera->GetViewMatrix() , 
                                   m_Camera->GetProjectionMatrix() , 
                                   m_Objmanager);	
	
	
//...
//some code
//...
	
	
	return true;
}

As you can see, i'm passing camera and objmanager singletons, can I call this singleton inside m_renderer->Frame? (previously i was using this and had too many problems, so i started to pass everything i need)

sorry about my english

Thanks!

Advertisement
5) Should I choose another pattern rather than building a sticky mess of singleton spaghetti?

Yes. The answer is yes.

Hi, I'm new in the singleton world, I used to think that i was using singletons, but really i was using static variables instead tongue.png

Just stick to the static variables. At least with those, the evil is not hidden beneath the surface.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Now i Have this:


//Singleton
	static Core* GetInstance()
	{
		if (!m_Core)    <----I forgot this
		m_Core = new Core;		
		return m_Core;
	}


5) Should I choose another pattern rather than building a sticky mess of singleton spaghetti?

Yes. The answer is yes.


Just stick to the static variables. At least with those, the evil is not hidden beneath the surface.

but... now, with singletons my life is easier, and only I have like four of them.

Anyway a singleton is static, so , what's the difference between define a static variable at the end of the class and create a singleton?


now, with singletons my life is easier

Can you explain why you think your life is easier with singletons? I'm not quite clear as to what benefit you perceive over a static variable.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I don t see how it's easier. You have a memory leak and are unsure how to utilize the singleton pattern.

1) The answer is obvious once you understand the singleton pattern.

2) This is the problem with singletons and why you're being guided away from them. The order of initialization is not absolute.

3) I don't quite understand this question.

4) This is the opposite of the design pattern you're using.

Simply put: inside of the singleton class you would use your members. Outside you would use GetInstance().

In my opinion singletons shouldn't be avoided at all costs, but it's not the greatest choice here.

In the end you're attempting to use a pattern that causes a lot of problems without understanding it or the problem it causes.

I don t see how it's easier. You have a memory leak and are unsure how to utilize the singleton pattern.

1) The answer is obvious once you understand the singleton pattern.

2) This is the problem with singletons and why you're being guided away from them. The order of initialization is not absolute.

3) I don't quite understand this question.

4) This is the opposite of the design pattern you're using.

Simply put: inside of the singleton class you would use your members. Outside you would use GetInstance().

In my opinion singletons shouldn't be avoided at all costs, but it's not the greatest choice here.

In the end you're attempting to use a pattern that causes a lot of problems without understanding it or the problem it causes.

Thanks!

before use singletons i was defining every manager (renderer, core, objmanager) like a static object. I was getting some errors.
From the book "game engine architecture" I read how to implement this managers, and the author used singletons, so this is why I used them.sleep.png

Give me an example on how implement a class with a static object, and maybe I will be convinced. cool.png


Give me an example on how implement a class with a static object, and maybe I will be convinced

Make a static pointer to the class, instead of a static instance. That way you can manually initialise them in the correct order from your main function (this is literally the only difference between your static objects and your current singleton implementation).

However, I assure you that in the long run, you would be better off not using static objects at all (including Singletons). Just allocate these objects in your main function, and pass pointers to them around as needed.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Upon further review (sorry, I was viewing via my phone earlier and missed some of the code) you're heavily mixing design patterns here. I didn't realize the other classes were singletons as well.

With singletons, the idea is that you utilize ClassName::GetInstance() when interacting with the singleton. This ensures that, wherever you access it, you will always get back an instantiated class. Thus, storing them internally (m_renderer, m_Objmanager, etc.) is the opposite of what you're trying to achieve. The "GetInput()" and "GetRenderer()" and such are breaking the pattern. Calling "Core::GetInstance()->GetRenderer()" will result in a null pointer until after Core has been initialized. It also makes no sense: why would you call Core::GetInput() rather than InputClass::GetInstance()?

Static variables were only offered up as lesser of two evils. The way I would design it is very simple: I'd have a core class that contains instances of all of my core types (renderer, input, etc.) I'd instantiate it in WinMain(), call Initialize(), call Run() and then any class/function that needs something contained in it would get passed a pointer.

2) This is the problem with singletons and why you're being guided away from them. The order of initialization is not absolute.

This is actually wrong, singletons(at least by the design of the pattern) will always be constructed with the first call to whatever Get function you are using.

Static is a bit of a confusing keyword in C++ since it means different things in different places. The construction order issue is relegated to any kind of global object since global instances are not contained in a function there is no logical way to construct them from scoped code. In terms of global object the word static simply affects the linkage of the object.

A lot of people have issues with singletons for two seperate but related reasons. The first is that singletons are essentially masquerading globals, their construction is hidden in a function call but due to the Get call having to be static they are essentially globals, there will only be one created during the program lifetime and it is accessible from anywhere. The second issue and more prevalent one is that good engineering practice tends to say that globals are signals of bad code, they ironically create tight coupling by being accessible from anywhere because a complex weave of object interrelations begins to form between game and engine objects and the often large global "subsystems" that people make, i.e. a renderer, a state manager.

I can briefly go over the difference between a global and the different static constructs.

Global variables are technically any variable declared at global(program) scope. By itself a global isn't very useful, if you declare an int value in a header file and include it more than once it will cause linking errors(possibly compilation) since you will get multiply defined symbols. By declaring a global as extern and defining it ONCE(in a cpp file) all code can reference that one variable.

Which brings us to our uses of static:

  • Static on a global variable gives it internal linkage, this means the variable can be included by multiple files but each that includes it will get its own copy of the variable, they won't be shared and modifying one will not affect the others. Linkage basically refers to whether the variable will be visible and possibly accessible to other compilation units.
  • Static on a member variable is a bit different, it essentially means that the variable belongs to the class itself and only one will exist between all instances of the class.
  • Static on a member function has more or less the same effect as above, the function can be accessed through the class name itself and thus the function can't interact with any member variables of the class since it isn't actually part of any particular instance(there may not even be any.)
  • Static on a variable declared inside a function means the variable will be initialized only when the function is first called and will retain that state between function calls.

Using the above, a singleton must be created by at the very least having a static variable representing itself or in reference to itself. You could do that with a static function containing a static object declaration, that would create the object on first function call.

Either way the point is that a singleton is just a trick essentially in order to control the order of instantiation with a global, the same could be attained by only constructing globals with basic functionality and doing actual startup through an Init function. The book the OP referred to actually describes this quite a bit in detail, and he also later describes the singleton pattern as being semi-commonly used in game development but not necessarily ideal.

This topic is closed to new replies.

Advertisement