¿Es mi plantilla singleton realmente un singleton?

Me dijeron que mi plantilla singleton puede no ser realmente un singleton, ya que hay formas de crear más de un objeto con ella. Cuando pregunté cómo solucionarlo, me ignoraron. Es por eso que vengo a preguntar si mi clase de plantilla singleton es realmente un singleton.

#ifndef SINGLETON_H_
#define SINGLETON_H_

template <class T>
class Singleton
{
private:
static T* instance;

protected:
    Singleton<T>(  )
    {
    }

public:
    static T* getInstancePtr(  )
    {
        if ( instance == 0 )
            instance = new T(  );

        return instance;
    }
};

template <class T> T* Singleton<T>::instance = 0;

#endif

Luego, esto es heredado por una clase que deseo que sea un singleton así: -

class Console : public Singleton< Console >
{
};

preguntado el 29 de junio de 12 a las 20:06

Has probado a compilar Console c1, c2; ? -

Acabo de encontrar una forma de eludir la instancia única. Si inicializo la consola con Console c1; Tengo una instancia de Consola para c1 y una segunda instancia de Consola en el puntero de instancia en la clase Singleton. -

6 Respuestas

Has creado el constructor predeterminado. protected. La clase derivada puede acceder a ella, por lo que compilará:

Console c1, c2;

Respondido el 29 de junio de 12 a las 20:06

No vuelva a publicar los comentarios de otras personas como respuestas. - Nikolái Fetissov

@Charles La Q ha sido editada, ahora hay una definición. @Nikolai ¿Alguna vez has escrito std::string str;? Yo también lo hice. - jrok

@Nikolai: Y a veces también es la única forma de publicar una respuesta correcta, por lo que la pregunta no permanece abierta para siempre. Si Charles quisiera publicar una respuesta, estoy seguro de que lo habría hecho. - ildjarn

@NikolaiNFetissov: No veo cómo es de mala educación. Publiqué un comentario para incitar al autor de la pregunta a asegurarse de que su ejemplo estaba completo. Además, mi comentario era una pregunta; esta es una respuesta verdadera. - CB Bailey

Una razón simple por la que no puede garantizar que sea un singleton se debe a la seguridad de subprocesos.

Si dos o más subprocesos llaman a getInstancePtr al mismo tiempo, puede terminar con dos o más instancias dependiendo del intercambio de subprocesos.

Respondido el 29 de junio de 12 a las 20:06

La pregunta del OP no tiene nada que ver con los subprocesos múltiples, y los Singleton tampoco son exclusivos de los subprocesos múltiples. - etiquetador de teléfono

Utilizar variable estática local para implementar el patrón singleton:

template <class T>
class Singleton
{
    static T* getInstancePtr(  )
    {
        static T instance; // <-- HERE

        return &instance;
    }
};

Aparte de mucho menos código, también está garantizado que es seguro para subprocesos. Se construirá en la primera convocatoria de Singleton<X>::getInstancePtr() y las llamadas sucesivas obtendrán una instancia.

Alternativamente, si desea una instancia por hilo, puede usar thread_local en lugar:

template <class T>
class Singleton
{
    static T* getInstancePtr(  )
    {
        thread_local T instance; // <-- HERE

        return &instance;
    }
};

contestado el 12 de mayo de 13 a las 08:05

Usé la misma plantilla singleton que usted, pero dejo que el usuario cree constructores y destructores privados. el usuario tendrá que hacerse amigo de la clase singleton, pero está cerca de lo que quiero y se puede usar como singleton. No es seguro para subprocesos (todavía), pero 'resuelve' el problema de múltiples instancias.

contestado el 12 de mayo de 13 a las 08:05

Para trabajar en un entorno multiproceso, necesita una solución diferente. Debe usar capacidades de lenguaje específicas para asegurarse de que solo se cree una instancia del objeto en presencia de varios subprocesos. Una de las soluciones más comunes es usar el lenguaje de bloqueo de doble verificación para evitar que subprocesos separados creen nuevas instancias del singleton al mismo tiempo.

Respondido el 29 de junio de 12 a las 20:06

La pregunta del OP no tiene nada que ver con los subprocesos múltiples, y los Singleton tampoco son exclusivos de los subprocesos múltiples. - etiquetador de teléfono

Ok, aparte de cualquier problema con subprocesos múltiples, hubo un caso en el que pude crear dos instancias. Al inicializar la consola de clase a continuación

class Console : public Singleton< Console >
{
};

al igual que

Console c1;

Estaba terminando con dos instancias de Console, una en el puntero de instancia que se encuentra dentro de la clase Singleton y otra dentro del objeto c1 en sí. Resolví esto cambiando la clase Singleton a la siguiente.

#ifndef SINGLETON_H_
#define SINGLETON_H_

template <class T>
class Singleton
{
private:
    static T* instance;

protected:
    Singleton<T>(  )
    {
        if ( instance == 0 )
            instance = static_cast<T*>(this);
    }

public:
    static T* getInstancePtr(  )
    {
        return instance;
    }
};

template <class T> T* Singleton<T>::instance = 0;

#endif

Sin embargo, aparte de los problemas de subprocesos múltiples, ahora estoy más seguro de que mi clase Singleton tendrá menos probabilidades de generar múltiples instancias.

Respondido el 29 de junio de 12 a las 21:06

Eso no lo resuelve. instance apuntará a la primera instancia construida, pero aún puede construir de manera predeterminada tantas instancias de clases derivadas como desee (a menos que haga que los constructores de clases derivadas también sean privados). ideone.com/Y0zPo - jrok

Lo arreglé y agregué Singleton como amigo a las clases que lo heredan. Gracias :) - ctor

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.