Stuck on singleton constructors

Started by
7 comments, last by EvilKind 19 years, 11 months ago
If you use a singleton template can you still do stuff in the constructor of the class created from the template? Below is the code I have been looking at. For example I have been trying to assign a number in the constructor and read it, can this be done, if so where am i going wrong? Thanks a million!


#ifndef SINGLETON_H
#define SINGLETON_H

#include <cassert>

template <typename T> class Singleton
{
public:
	Singleton(void)
	{
		assert(m_pObj == 0 && "Only one instance of this class is permitted.");
		m_pObj = static_cast<T*>(this);
	}
	~Singleton(void)
	{
		assert(m_pObj != 0 && "The singleton instance is invalid.");
		m_pObj = 0;
	}
	static T& Instance(void)
	{
//		assert(m_pObj != 0 && "The singleton has not yet been created.");

		return ( *m_pObj );
	}

private:
		static T* m_pObj;
};

template <typename T> T* Singleton <T>::m_pObj = 0;

#endif

#ifndef GRAPHICS_H
#define GRAPHICS_H

#include <iostream>

#define g_Graphics Graphics::Instance()

class Graphics : public Singleton <Graphics>
{
public:
	Graphics() : Singleton<Graphics>(*this)
	{
		num = 1;
		std::cout << "Graphics created!" << std::endl;
	};

	~Graphics()
	{
		std::cout << "Graphics destroyed!" << std::endl;
	};
	
	void Access()
	{
		std::cout << num << std::endl;
	};
	int num;
};

#endif

// Main

#include "Singleton.h"
#include "Graphics.h"

void main( void )
{
	g_Graphics.Access();
}
I got 2 books, one on game programming and another on miracles so I can understand.
Advertisement
Shouldn''t the #define g_Graphics Graphics::Instance() be defined after the class is?

What Singelton constructor do you call from the Graphics constructor? I can only see a constructor that takes no argument, so what''s that thing with "this"?
Shouldn''t the #define g_Graphics Graphics::Instance() be defined after the class is? - Doesn''t matter, still works!

What Singleton constructor do you call from the Graphics constructor? I can only see a constructor that takes no argument, so what''s that thing with "this"?

: Singleton(*this) - saw it being used with Greg Snook singleton class, so tried it, doesn''t matter if you delete it.

Graphics()
{
num = 1;
std::cout << "Graphics created!" << std::endl;
};

Wanted to assign the num in the constructor and read it in another function, make sense?
I got 2 books, one on game programming and another on miracles so I can understand.
quote:class Graphics : public Singleton<Graphics>


I have a feeling this circularity will be a problem.

[edited by - Zahlman on May 18, 2004 2:10:58 AM]
here is a quick and dirty singleton example

/////////////////////////////////////////////////// singleton.h file#ifndef singleton_h#define singleton_hclass CSingleton{public:   static CSingleton* get_instance();private:   CSingleton();   ~CSingleton();   static CSingleton*  instance;};#endif////////////////////////////////////////////// singleton.cpp fileCSingleton* CSingleton::instance = NULL;CSingleton::CSingleton(){}CSingleton::~CSingleton(){  if (instance != NULL)  {     delete instance;  }}CSingleton* CSingleton::get_instance(){  if (instance == NULL)  {    instance = new CSingleton;  }  return instance;}



"A soldier is a part of the 1% of the population that keeps the other 99% free" - Lt. Colonel Todd, 1/38th Infantry, Ft. Benning, GA
quote:Original post by Zahlman
quote:class Graphics : public Singleton<Graphics>


I have a feeling this circularity will be a problem.


Not really, it''s a fairly common construct in generic programming. It''s common enough that it''s even been labelled a pattern. See: Coplien, J., "Curiously Recurring Template Patterns", C++ Report, February 1995, pp. 24-27.
I was just getting ready to crash when I saw this - unless I missed something I dont think that you are creating the object at all. Here''s some snapshots of the code I use in a project that''s been dead for a while:

Singleton.h
///////////////////////////////////////////////////////////////////////////////////	singleton.h////	Singleton template////	Encapsulates the mechanisms for doing a singleton into a template.  To use//	the template singleton you only need to derive your class from the singleton//	(singleton acts as a base class) and use THE SAME class name as the //	typename.  For example:////	class foo : public Singleton<foo>//	{//		someMethod();//	};////	Then the only other requirement is to ensure that you allocate the object//	somewhere in the code ( preferably as early as possible ).  Then you can//	access the object in the following manner:////	#define	g_foo	foo::getInstance()//	foo		foo_Object;////	g_foo.someMethod( ARGS );////	It is recommended that the define go with the declaration/definition of the//	singleton class so that it is easily propogated to all users of the class.////	Original idea in Game Programming Gems 1 by Scott Bilas	//	Idea simplified by Greg Snook///////////////////////////////////////////////////////////////////////////////#ifndef singleton_h__#define	singleton_h__//	Disable the warning regarding ''this'' pointers being used in base member initializer list.#pragma warning(disable : 4355)template<class T> class Singleton{public:	Singleton(T& obj)	{		_ASSERT( !m_Singleton );		m_Singleton = &obj	}	~Singleton()	{		_ASSERT(m_Singleton);		m_Singleton = 0;	}	static T& __fastcall getInstance(void)	{		_ASSERT(m_Singleton);		return (*m_Singleton);	}	static T* __fastcall getInstancePtr(void)	{		return (m_Singleton);	}private:    Singleton( const Singleton& Src);    Singleton& operator=( const Singleton& Src);	static	T*	m_Singleton;};template<class T> T* Singleton<T>::m_Singleton = 0;#endif


apptimer.h
///////////////////////////////////////////////////////////////////////////////////	AppTimer.h////	Declares a very simple timer mechanismm largely borrowed from the DX sdk//	to provide frame-basd timing in the game.  For profiling, you should use//	the Profiler class instead.///////////////////////////////////////////////////////////////////////////////#ifndef	apptimer_h__#define	apptimer_h__/////////////////////////////////////////////////////////////////////////////////	Valid AppTimer commands///////////////////////////////////////////////////////////////////////////////enum TIMER_CMD{	TIMER_RESET,			//	to reset the timer	TIMER_START,			//	to start the timer	TIMER_STOP,				//	to stop (or pause) the timer	TIMER_ADVANCE,			//	to advance the timer by 0.1 seconds	TIMER_GETABSOLUTETIME,	//	to get the absolute system time	TIMER_GETAPPTIME,		//	to get the current time	TIMER_GETELAPSEDTIME,	//	to get the time that elapsed between TIMER_GETELAPSEDTIME calls};class AppTimer : public Timer, public Singleton<AppTimer>{public:	AppTimer();	~AppTimer();	F32 __fastcall useAppTimer(TIMER_CMD cmd);private:	S64		m_lastElapsedTickCount;	S64		m_baseTicks;	S64		m_stopTicks;	S64		m_ticksPerSec;	F64		m_oneOverTicksPerSec;};#define	g_appTimer	AppTimer::getInstance()#endif	//	__APPTIMER_H__


apptimer.cpp
///////////////////////////////////////////////////////////////////////////////////	AppTimer.cpp////	Declares a very simple timer mechanismm largely borrowed from the DX sdk//	to provide frame-basd timing in the game.  For profiling, you should use//	the Profiler class instead.///////////////////////////////////////////////////////////////////////////////#define		WIN32_LEAN_AND_MEAN#define		WIN32_EXTRA_LEAN#define		VC_EXTRALEAN#define		STRICT#include	"stdincludes.h"#include	"stddefines.h"#include	"data_types.h"#include	"debug_assert.h"#include	"sysinfo.h"#include	"bitflags.h"#include	"singleton.h"#include	"timer.h"#include	"apptimer.h" //////////////////////////////////////////////////////////////////////////////////	Default Construction / Destruction////////////////////////////////////////////////////////////////////////////////AppTimer::AppTimer()		 :Singleton<AppTimer>(*this),		  m_lastElapsedTickCount(0), m_baseTicks(0), m_stopTicks(0),		  m_ticksPerSec(0), m_oneOverTicksPerSec(F_ZERO){	m_ticksPerSec			= Timer::getTickRate();	m_oneOverTicksPerSec	= Timer::getOneOverTickRate();	useAppTimer(TIMER_RESET);}AppTimer::~AppTimer(){}/////////////////////////////////////////////////////////////////////////////////	useAppTimer()//	This is where it all happens.  The implementation is largely borrowed from//	the DX sdk.  I have converted it into a class so that the singleton template//	could be used without black Magic or the sacrifice of virgins...////	I stripped the core timing functionality out and base classed it as that//	will also be used in the profile classes.  This also allowed me to clean//	this class up a little bit and still keep different methods of timer//	functionality.///////////////////////////////////////////////////////////////////////////////F32 __fastcall AppTimer::useAppTimer(TIMER_CMD cmd){	S64		currentTicks;	F64		elapsedTime;	//	Get the current time setting.	if( m_stopTicks != 0 && cmd != TIMER_START && cmd != TIMER_GETABSOLUTETIME )	{		currentTicks = m_stopTicks;	}	else	{		getTickCount(currentTicks);	}	switch(cmd)	{		case TIMER_GETELAPSEDTIME:			elapsedTime = (F64) (currentTicks - m_lastElapsedTickCount) * (F64) m_oneOverTicksPerSec;			m_lastElapsedTickCount = currentTicks;			return (F32) elapsedTime;		case TIMER_GETAPPTIME:			return (F32) ( (F64) (currentTicks - m_baseTicks) * (F64) m_oneOverTicksPerSec );					case TIMER_RESET:			m_baseTicks				= currentTicks;			m_lastElapsedTickCount	= currentTicks;			return F_ZERO;		case TIMER_START:			m_baseTicks += currentTicks - m_stopTicks;			m_stopTicks = (S64) 0;			return F_ZERO;		case TIMER_STOP:			m_stopTicks				= currentTicks;			m_lastElapsedTickCount	= currentTicks;			return F_ZERO;		case TIMER_ADVANCE:			m_stopTicks += (S64)(m_ticksPerSec * 0.1);			return F_ZERO;		case TIMER_GETABSOLUTETIME:			elapsedTime = currentTicks * (F64) m_oneOverTicksPerSec;	}	DEBUG_ASSERT(false, "Should Not Get Here");	return F32_MIN;}


main.cpp
#define MAX_LOADSTRING 100// Global Variables:HINSTANCE			hInst;TCHAR				szTitle[MAX_LOADSTRING];TCHAR				szWindowClass[MAX_LOADSTRING];RenderDlg			renderDlgObj;GETINTERFACEPROTO	getInterface	= NULL;GETRELEASEPROTO		release			= NULL;Sysinfo*			g_sysinfo		= NULL;//	SingletonsProfileManager		profileManager;AppTimer			applicationTimer;// Foward declarations of functions included in this code module:ATOM				MyRegisterClass(HINSTANCE hInstance);BOOL				InitInstance(HINSTANCE, int);LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);void				runTest(HWND);int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){	PROFILE_SCOPE("WinMain")etc...


The singleton class basically hides/restricts your access to the pointer but you do have to create it at some point. It is possible to have the singleton class create the object when the first request is made for it, but then you need to worry about how it gets released. If you are using smart pointers of some sort you should be ok.


Anyhow - hope that helps, if I missed something in your code just disregard....


#dth-0
"C and C++ programmers seem to think that the shortest distance between two points is the great circle route on a spherical distortion of Euclidean space."Stephen Dewhurst
Yes you were right! Thanks xiuhcoatl and again for the example code.
I got 2 books, one on game programming and another on miracles so I can understand.

This topic is closed to new replies.

Advertisement