Foros - Stratos

Programadores => Código de la Semana => Mensaje iniciado por: ethernet en 27 de Abril de 2003, 05:32:27 PM

Título: Singleton - CordayUK & otros
Publicado por: ethernet en 27 de Abril de 2003, 05:32:27 PM


/*

CSingleton.h   (basado en el Game Programming Gems I)



Define una clase singleton. Deriva tus clases a partir de esta y podras llamarlas desde cualquier punto de tu juego.



ejemplo:



en tu clase CJuego tienes un objeto CTimer, el cual esta implementado en CTimer.h asi:



  Class CTimer : public CSingleton <CTimer>



desde cualquier otra parte de tu juego que incluya CTimer.h puedes llamar a CTimer::GetSingletonPtr () y obtener un

puntero al Timer. Por supuesto solo puedes tener un objeto CTimer en todo el juego.



*/







#pragma once

#pragma warning( disable : 4311 4312 )   //4311,4312 : unsafe cast from int to class pointer





#include <cassert>





#define SINGLETON_ERROR_MSG   "Algo va mal con el singleton!! :("



template <typename T> class CSingleton

{



  //puntero al singleton

  static T* ms_ptr;                                    



public:



  CSingleton (void)

  {

     assert (!ms_ptr && SINGLETON_ERROR_MSG);



     //averigua la direccion relativa de la instancia derivada

     spI offset = (spI)(T*)1-(spI)(spSingleton <T>*)(T*)1;



     //graba el resultado en el puntero del singleton

     ms_ptr = (T*)((int)this+offset);                    

  }



  virtual ~CSingleton (void)

  {

     assert(ms_ptr && SINGLETON_ERROR_MSG);

     ms_ptr = 0;

  }



  //devuelve la referencia al singleton

  inline static T& GetSingleton (void)

  {

     assert (ms_ptr && SINGLETON_ERROR_MSG);

     return (*ms_ptr);

  }



  inline static T* GetSingletonPtr (void)

  {

     spAssert (ms_ptr && SINGLETON_ERROR_MSG);

     return (ms_ptr);

  }

};



//inicializa el puntero a nulo

template <typename T> T* CSingleton <T>::ms_ptr = 0;





Esta es la implementación que yo propongo





template <class T> class Singleton : public T

{

private:



    Singleton() {     }

    Singleton(const Singleton& fact) {     }

    Singleton& operator = (const Singleton& fact) {     }

public:

    ~Singleton() {     }

public:

    static Singleton& Instance() {

        static Singleton s_instance;

        return s_instance;

    }

};





Como veis el destructor esta como public, teóricamente se debería poner como private pero  para mantener la implementación original , que esta así debido a un bug del msvc++, he decidido no cambiarla.

Espero que el autor no se me enfade por postearla sin su permiso ;P

Título: Singleton - CordayUK & otros
Publicado por: Zaelsius en 28 de Abril de 2003, 02:17:21 PM
Yo también leí el thread de FlipCode hace tiempo, cuando estaba buscando una correcta implementación del estereotipo . El código que yo uso es prácticamente idéntico al de Ethernet, con las siguientes diferencias:

1º) No derivo de T la clase Singleton.(¿Cómo influye ésto?)

2º) Declaro (static T* m_pInstance;) como miembro de la clase,
  y en Instance() tengo


if(!m_pInstance)m_pInstance = new T;

  return m_pInstance;


   Que es lo mismo que hace Ethernet con



 // Crea la instancia de clase al ser requerida por primera vez

static Singleton s_instance;



3º) Tambien tengo una pequeña macro que llamo desde los .CPP de la clase


#define DECLARE_AS_SINGLETON(T) T* T::m_pInstance=NULL



   Luego hago DECLARE_AS_SINGLETON(CTimer); p.ej.

El 3º punto es consecuencia directa del 2º. Con la implementación que propone ethi no hace falta...

Por cierto, el constructor de CordayUK me parece demasiado hardcore... ¿Funciona/deberia funcionar en cualquier compilador de C?[/code]
Título: Singleton - CordayUK & otros
Publicado por: ethernet en 28 de Abril de 2003, 02:31:32 PM
Umh, cuidado, porq declarar un static T *instace; en la clase no es lo mismo q tener un static en un metodo. Fijate q si tienes un static como miembro lo tienes q declarar y lo tienes q hacer en un cpp con la putada q conlleva ese tema unido a templates. Con la implementacion que yo he posteado (q no es mia) no tienes q preocuparte de ese problema.

Por lo demas estoy pensando el porq de derivar de la clase q queremos singletonizar (xDD parece sincrorzzrzzrr)

saludos
Título: Singleton - CordayUK & otros
Publicado por: ethernet en 28 de Abril de 2003, 02:36:13 PM
ah, ya veo, parece ser q es para llamar al destructor (de la base claro :)una vez terminada la ejecucion, asi no tienes q preocuparte de hacer un delete con el singleton q propone zaelsius. Eso es lo unico q se me ocurre

saludos
Título: Singleton - CordayUK & otros
Publicado por: ethernet en 28 de Abril de 2003, 02:46:14 PM
por cierto:


  #define DECLARE_AS_SINGLETON(T) T* T::m_pInstance=NULL


no seria ? :


#define DECLARE_AS_SINGLETON(T) T* Singleton<T>::m_pInstance=NULL

Título: Singleton - CordayUK & otros
Publicado por: CoLSoN2 en 28 de Abril de 2003, 03:01:26 PM
                               
CitarPor cierto, el constructor de CordayUK me parece demasiado hardcore...
yo ni lo entiendo xDDDD

lo de ::instance() { static singleton inst; return inst; } me parece mejor que usar un miembro static.

yo también uso unas macros de este rollo:

#define singleton Singleton::getInstance()

evidentemente para la clase base no sirve de nada, pero si para algo tipo game, npcManager, sceneManager, etc.                                
Título: Singleton - CordayUK & otros
Publicado por: Zaelsius en 28 de Abril de 2003, 06:20:44 PM
Tengo un par de problemillas, y no sé si es cosa mia:

- El compilador(VS.NET) se queja de que hay que definir T antes de Singleton, pero se supone que es al revés ¿?
Vamos, que no me deja derivar Singleton de T.

- Si tengo, una clase p.ej. Singleton, no veo manera de llamar a funciones miembro no estáticas de MyClass.
Sólo puedo llamar a funciones declaradas static...el caso es que con mi Singleton yo hacía algo parecido a esto MyClass::Instance()->Foo() y ahora no puedorrl!!
Esto último es sin poder derivar Singleton de MyClass(¿está relacionado?, o Singleton Sux.. :-D)

Bueno, propongo a los del ISO C++ que incorporen al lenguaje una puñetera plantilla SIngleton estándar...
#include rulez!! :-D

Tambien he investigado un poco por ahí y he llegado a ver implementaciones académicas de Singleton de 3 páginas...haciendo movidas impresionantes
Título: Singleton - CordayUK & otros
Publicado por: ethernet en 28 de Abril de 2003, 07:41:13 PM
XD, yo no he probado el codigo, pero se de buena fuente q funciona. No deberia fiarme pero bah! xD.

zaelsius, donde has visto esas implementaciones de singleton?

A mi no me gusta usar singletones, prefiero usar un pattern façade si no quiero emborronar mucho el codigo y lo de tener solo una instacia ya me las apaño yo xD

saludos
Título: ......
Publicado por: Grugnorr en 28 de Abril de 2003, 11:23:01 PM
                                Esa implementación del Singleton es la de Bilas en el Gems1.

Aquí tenéis el link dentro de su web:
http://www.drizzle.com/~scottb/publish/gpg...1_singleton.htm

La movida del constructor está *explicada* aquí:

Citar
So how does this work? All of the important work is done in the Singleton constructor, where it figures out the relative address of the derived instance and stores the result in the singleton pointer (ms_Singleton). Note that the derived class could be deriving from more than just the Singleton, in which case "this" from MyClass might be different from the Singleton "this". The solution is to take a nonexistent object sitting at address 0x1 in memory, cast it to both types, and see what the difference is. This will effectively be the distance between Singleton and its derived type MyClass, which it can use to calculate the singleton pointer.

Cada implementación de un singleton tiene algún defecto, el Singleton del Design Patterns no llama al destructor, así que aunque la memoria se libere por el SO, las demás cosas que debieran ser liberadas no lo son :S. Éste singleton es...lioso y no sé si tenía algún fallo más.

El libro Modern C++ Design tiene un capítulo dedicado a Singletons, del que se deduce que no existe una implementación óptima de entre las que presenta, pero hay algunas que yo consideraría lo suficientemente general y efectiva, registrando la función que libera recursos con atexit()


PD: El Singleton que hice yo a partir del Phoenix Singleton del Modern desapareció con algún formateado....no lo encuentro :(                                
Título: Singleton - CordayUK & otros
Publicado por: Zaelsius en 28 de Abril de 2003, 11:25:22 PM
                                Puede que sean cosas mias...XD

Las implementaciones las ví buscando en Google. Eran "papers" de profesores de universidades...

Edit: He encontrado uno de los documentos que me dejó traspuesto:http://www.cs.technion.ac.il/~gabr/papers/...ngleton_cuj.pdf

Correis peligro de volveros locos si llegais a la última página  :X9:                                
Título: Singleton - CordayUK & otros
Publicado por: CordayUK en 02 de Mayo de 2003, 07:06:21 PM
                                exacto como dice Grugnorr, el singleton que yo mande esta sacado del game gems I (ademas lo pone en el codigo comentado). el motivo de calcular la posicion del puntero asi es simplemente por si tu objeto singleton deriva de alguna otra clase ademas de la plantilla singleton. pero no es totalmente necesario, podeis suprimir esos pasos y ya esta :)                                
Título: Singleton - CordayUK & otros
Publicado por: O2 en 23 de Julio de 2003, 06:53:12 PM
 Me pasa lo mismo que comenta Zaelsius:

VS.NET no me deja hacer:

template<typename Type>
class CSingleton : public Type {


Me dice que hay que definir Type primero.

He tenido que recurrir a dejar los constructores y destructores de "Type" (en este caso CWindow) como publicos, pues sino CSingleton no puede llamar a ellos y no puede hacer el new apropiado.

Alguna sugerencia?