Archived

This topic is now archived and is closed to further replies.

EvilKind

Stuck on singleton constructors

Recommended Posts

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();
}

Share this post


Link to post
Share on other sites
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"?

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
here is a quick and dirty singleton example


/////////////////////////////////////////////////

// singleton.h file


#ifndef singleton_h
#define singleton_h

class CSingleton
{
public:
static CSingleton* get_instance();

private:
CSingleton();
~CSingleton();
static CSingleton* instance;

};

#endif



////////////////////////////////////////////

// singleton.cpp file


CSingleton* 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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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;

// Singletons

ProfileManager 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

Share this post


Link to post
Share on other sites