Static class

Started by
6 comments, last by Zahlman 18 years, 9 months ago
Im writing a wrapper class for sdl. That class loads stores and draws my images. There is no need to have more than one instance of this class (in fact it would be a pain cause I dont know in which class a particular image has been loaded). What is the best way to make sure there is only one instance of a class? The static keyword? Should I make everything static? Searched a bit for static tutorials but couldnt find anything good. Heres the class as it is now (cut down)

class SdlWrapper {
private:
	void	Slock(SDL_Surface *screen);	// lock and unlock
	void	Sunlock(SDL_Surface *screen);

	std::map	<std::string, SDL_Surface*> Bmp;	// holds all the texture

	SDL_Surface *screen;	// the visible screen

	int		ResX; 
	int		ResY;		// the screen resolution

public:
	SdlWrapper(int resolutionX, int resolutionY, int depth);

	// bmp handling functions
	bool			LoadBmp(std::string filename);	// adds a texture to the texture map, return false on failure	
		
	void	DrawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B);	// draw a single pixel
	
	void	DrawImg(std::string img, int x, int y);		// draws the image at those coordinates on the screen background onto the screen
	void	Flip()		{SDL_Flip(screen);}				// flips and updates the entire screen	
};



What should be made static?
Advertisement
I hesitate to say make it a singleton especially because Washu would probably kill me. [wink] Anyway, sure if that class is as detailed as it is, surely you'd realise if you created more than one? If you don't need that class more than once, just don't create more than one instance of it.

Before looking at the singleton approach, which seems like overkill to me personally, read the topics in Washu's Journal, "Why are you infected with Singletonitis?" and "Singletonitis, Part 2". They're on the first page at the bottom. [smile]
the two common solutions are Singleton and Monostate mentioning either gets all sorts of inflamatory responses about your lack of abstration, encapsulation and that your father smells of elderberries.

There's a lot to read, and most of it should perusade you into concluding that Singleton mostly is a Antipattern.

Basicly you probably should try to find another design, or just follow the clickies for advice.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
Sounds like a singleton to me.

There's various ways of implementing a singleton, each with their own advantages and disadvantages. Here's one example:

class blah{private:     blah() //constructor is private to prevent any old fool from creating one!    static blah* mpInstance;    // pointer to the only allowed instance of the classpublic:    ~blah()    {        mpInstance = 0;    }    static blah* GetInstance()    {        if(!mpInstance)        {            mpInstance = new blah;        }        return mpInstance;    }}


blah::GetInstance() creates the class if it doesn't already exist. To delete it, just call delete blah::GetInstance().

EDIT: beaten, twice. Also, I agree with the general point made above, that the Singleton class is one of the most abused design patterns ever, and is rarely, if ever necessary. And can be a right pain in the arse if it turns out that what you thought was a valid candidate for a singleton turns out not to be...
Yeah I tried that singleton style... But it didnt work out all that way. Is static no good? Ill look up that Monostate style.
Quote:Original post by Mizipzor
Yeah I tried that singleton style... But it didnt work out all that way. Is static no good? Ill look up that Monostate style.


what problem did you encounter with the singleton? it's most of the time pretty straightforward getting it to work although it sometimes leaves a bit of a stink in the codebase...

HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
Well the problem was some circular dependencie issues, two singleton classes wanted an instance of each other. A calls B's getinstance(), B's pointer is not yet filled so it makes a class. In B's constructor it requests a pointer to an instance of A, it calls A's getinstance(). A's pointer is unfilled so an instance is created. In A's constructor it wants and instance B so it calls B's getinstance... ... ...

I solved that by moving all the init stuff out of the constructor and into an init() function. Then made a class of everyone singletong class and then called thier init functions.

[edit] Maybe I use that way with init functions. But the singleton code can really clutter a class. Isnt there any way to inherit it from a CSingleton_Base? I havent done any class inheritence before but whats hard here (I imagine) is that the singletong pointer cant be specified as that needs to be changed to whatever class name it now is.

Here I have my AsciiMap class cut down to only whats singleton. Is there a way to move this to a base class?
class AsciiMap {	// SINGLETON ---protected:	static AsciiMap* m_pInstance;	AsciiMap( void ) { };public:	static AsciiMap* GetInstance( void ) {		if ( !m_pInstance )			m_pInstance = new AsciiMap();		return m_pInstance;	}	static void DeleteInstance(void) {		delete m_pInstance;		m_pInstance = 0;	}};


[Edited by - Mizipzor on July 20, 2005 8:59:54 AM]
Note: the bit after the horizontal bar is important! :)

Quote:What is the best way to make sure there is only one instance of a class? The static keyword? Should I make everything static? Searched a bit for static tutorials but couldnt find anything good.


That's baaaaaaaasically how I do it, but that's because I'm using Java where I *have* to make a class. And then again, a lot of the more knowledgable people around here think I'm nuts (and not just because of using Java ;) ).

But to me, it smells like a traditional C-style module, perhaps using a namespace for scoping. In C++ that avoids typing out the 'static' keyword all over the place, because now you just have free functions anyway, and the file-globals already have static linkage.

// header#ifndef SDL_WRAPPER_H#define SDL_WRAPPER_H#include "SDL/SDL.h" // users won't include this directly// Don't refer to "private" stuff in the header.// TODO: namespacing// Set up SDL.void init(int resolutionX, int resolutionY, int depth);// bmp handling functions// Attempt to load a texture and register it. Return whether successful.	bool LoadBmp(std::string filename);// Draw a single pixel to screen, at the indicated location with indicated colour.void DrawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B);	// Draw a previously loaded texture at the indicated position.void DrawImg(std::string img, int x, int y);// Refresh the screen by flipping the double buffer.void Flip(); // we don't get to put it in the header any more, except by// exposing the 'screen' data :/#endif// implementation#include "sdl_wrapper.h"// "private" globals// registry for textures loaded via LoadBmpstd::map <std::string, SDL_Surface*> BMPs;// the visible screenSDL_Surface *screen;// the screen resolutionint ResX; int ResY;// Since we always know which SDL_Surface will be used, no need for the parameter.void Slock() { /* implement */ }void Sunlock() { /* implement */ }void init(int resolutionX, int resolutionY, int depth) { /* implement */ }bool LoadBmp(std::string filename) { /* implement */ }void DrawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B) { /* implement */ }// FIXME: Should this try to LoadBmp if not already found?void DrawImg(std::string img, int x, int y) { /* implement */ }void Flip() { /* implement */ }


There are definite disadvantages here - a serious loss of flexibility, mainly, and the fact that Bad Things will definitely happen if you forget to init(), whereas the compiler could catch you if you forget to make an instance (although the compiler can't catch you making multiple instances, except via some Singleton pattern). That problem is doubled if you need to "tear down" the class as well. On the other hand, if you can deal with this kind of locking-down (and for a really big project, it will be hard to change back, and you'll probably have to recompile everything) you do get a fair bit simpler interface, because you're never passing around nor requesting a class instance, but just calling global methods.

Again, I work in J2ME where
a) this kind of thing *does* save some small amount of space
b) the small amount does take a bit of the pressure off
c) the project is small enough that I have a pretty good idea what the design will be anyway, and I don't mind so much about fixing it if I'm wrong

Oh, and this also works fairly well in plain C, where you basically have to build all your tools anyway - just build the simplest tool that will get the job done ;)



However, there certainly are options here for making instance objects - although at least the BMP registry will likely remain static (i.e. shared between the instances) anyway. For example, you could think in terms of a BMP wrapper class: constructor registers the this-object, and a draw member draws to a specified screen. Or, a "drawing pipeline" class: you specify a Surface in its ctor, and it draws provided BMPs and pixels to that surface during its lifetime by the draw method (by the way, you should consider just overloading the name "draw"), and then it automatically calls SDL_Flip in the dtor. That way you exploit RAII to hide one of the ickier details of the whole drawing process. :) A fair bit depends on whether there's any conceivable use for multiple surfaces in your system - I think you'll find there is (offscreen buffers).

This topic is closed to new replies.

Advertisement