c++ - singletons - singleton c#}
¿Cómo eliminar el puntero de Singleton? (6)
Estaba implementando un patrón de Singleton. Aquí, estoy creando una nueva instancia de Singleton * en GetInstance, cuando intento eliminarla en el destructor, lo hace en un bucle infinito. ¿Cómo evitar la pérdida de memoria en este caso?
Por favor, consulte el siguiente código:
#define NULL 0
class Singleton
{
private :
static Singleton* m_pInstance;
Singleton(){};
public :
static Singleton* GetInstance()
{
if(m_pInstance == NULL)
{
m_pInstance = new Singleton();
}
return m_pInstance;
}
~Singleton()
{
//delete m_pInstance; // The system goes in infinate loop here if i uncomment this
m_pInstance = NULL;
}
};
Singleton* Singleton ::m_pInstance = NULL;
int main()
{
Singleton* pInstance = Singleton::GetInstance();
delete pInstance;
}
Agregue un miembro estático Singleton::DestroyInstance()
que elimine la instancia y Singleton::DestroyInstance()
desde el main.
void Singleton::DestroyInstance() {
delete m_pInstance;
m_pInstance = 0;
}
/* ...................... */
int main()
{
Singleton* pInstance = Singleton::GetInstance();
/* ... */
Singleton::DestroyInstance();
}
Aquí hay una implementación más correcta de singletons:
class Singleton
{
public:
static Singleton& Instance()
{
static Singleton inst;
return inst;
}
protected:
Singleton(); // Prevent construction
Singleton(const Singleton&); // Prevent construction by copying
Singleton& operator=(const Singleton&); // Prevent assignment
~Singleton(); // Prevent unwanted destruction
};
La instancia estática se crea la primera vez que llama a Instance()
y se destruye cuando se cierra el programa.
Pero ten cuidado con el uso de singletons. No son malvados, como algunos aquí piensan que son (me parece que esa posición es irracional), pero son muy fáciles de usar mal y difíciles de usar correctamente. Como regla general, no use singletons para sus "clases de interfaz" (las que son utilizadas por otras partes del programa); intente usar singletons solo como detalles de implementación y solo cuando se considere apropiado.
Edición: un ejemplo de uso
Hace algún tiempo publiqué una respuesta en gamedev.stackexchange y la solución que propuse usaba singletons como parte de la implementación, no la interfaz. El código está comentado y explica por qué se necesitan singletons: https://gamedev.stackexchange.com/a/17759/6188
Por supuesto que causa un bucle infinito!
Llamas al destructor, pero el destructor también llama al destructor, así que el destructor llama al destructor otra vez ... y otra vez ...
Si desea usar eliminar , debe usarlo desde fuera del destructor y NO volver a llamarlo en el destructor.
Para hacerlo, puedes usar otro método estático que reflejará el método GetInstance () :
class Singleton
{
public :
...
// this method is a mirror of GetInstance
static void ResetInstance()
{
delete m_pInstance; // REM : it works even if the pointer is NULL (does nothing then)
m_pInstance = NULL; // so GetInstance will still work.
}
...
~Singleton()
{
// do destructor stuff : free allocated ressources if any.
...
}
Nota: las otras personas le advierten sobre el uso de un singleton y tienen razón porque este patrón a menudo se usa incorrectamente. Así que piensa antes de usarlo. Pero adelante, de todos modos, ¡esa es la buena manera de aprender!
Respuesta corta, no utilizar singletons.
Respuesta más larga, nunca llame a eliminar el puntero de singleton en main()
. Utilice algún tipo de objeto estático que eliminará el singleton cuando se llamen a otros indicadores de variables globales.
Si bien la mejor práctica es no usar el patrón de singleton en la mayoría de los casos, es una buena práctica usar variables locales estáticas en las funciones para crear singletons:
static Singleton& Singleton::GetInstance() {
static Singleton the_singleton;
return the_singleton;
}
Para dar una explicación de las mejores prácticas: Singleton-nage generalmente no es necesario a menos que tenga que representar un recurso verdaderamente global. Los Singletons sufren de todos los inconvenientes de las variables globales (porque son variables globales con algo de OO glaseado) y, a menudo, tienen poca justificación para ser verdaderamente singulares. El programador ingenuo podría querer implementar a God
como un objeto singleton. El programador inteligente no lo hace y se regocija cuando el cliente resulta ser un politeísta.
usando SingletonHolder of Loki-Library escrito por Andrei Alexandrescu.
#include "SingletonHolder"
class Singleton
{
//not allowed ctor
private:
Singleton()
{}
~Singleton()
{}
...
//Singelton on heap
friend struct Loki::CreateUsingNew<Singleton>;
}
Singleton& get_singleton_pointer()
{
return Loki::SingltonHolder<Singleton>::Instance();
}
En este ejemplo, el Singlton se eliminará mientras finaliza el programa. También hay alguna otra estrategia para crear un puntero de singleton usando malloc, static ... más detalles, visite: http://loki-lib.sourceforge.net/html/a00628.html
Alternativ puede crear singleton simplemente usando una variable estática:
template <typename T>
struct CreateUsingStatic
{
static T& get_T_singleton()
{
static T t;
return t;
}
};
class Singleton
{
...
private:
friend struct CreateUsingStatic<Singleton>;
}