2012-02-10 20 views
9

he conseguido suele utilizar para la implementación de un patrón singleton de esta manera porque es muy fácil:¿Hay algún problema con esta implementación de singleton?

class MyClass 
{ 
    public: 
     MyClass* GetInstance() 
     { 
      static MyClass instance; 
      return &instance; 
     } 

    private: 
     //Disallow copy construction, copy assignment, and external 
     //default construction. 
}; 

Esto parece significativamente más fácil que crear un puntero instancia estática, la inicialización en el archivo de origen, y el uso de memoria dinámica asignación en la función de instancia con guardias.

¿Hay algún inconveniente que no veo? Me parece seguro para subprocesos porque creo que el primer subproceso para llegar a la primera línea provocaría la creación de instancias, y parece agradable y conciso. Me imagino que tiene que haber un problema que no estoy viendo ya que esto no es común - me gustaría obtener algunos comentarios antes de seguir usándolo

+2

Podrías devolver un MyClass & en lugar de un MyClass * –

+10

¿Quieres decir, aparte del hecho de que es un singleton? http: // stackoverflow.com/q/137975/10077 –

+0

Sí, sí, sé que son un antipatrón (patrón) y deben evitarse :) Todavía estoy interesado en por qué esto puede no ser seguro para subprocesos. Sé que modificar los datos del singleton: los miembros deberían estar protegidos por mutex, pero pensé que su creación a través de esta función sería segura. –

Respuesta

3

Esto no es una solución inherente de threadsafe: durante la construcción de la instancia, otro subproceso puede adelantarse e intentar obtener la instancia, lo que resulta en una instancia doble o en el uso de una instancia no construida.

esto es manejado por varios compiladores mediante la adición de un guardia (en gcc, creo que es un indicador para deshabilitar este), porque no hay manera de protegerse esto con un mutex definida por el usuario.

+0

Entonces, ¿estás diciendo que incluso sabes que hay una variable estática aquí, más de uno puede crearse de alguna manera? –

+0

La instancia se inicializa con el primer uso de la función. Supongo que es más doble inicializado que doble instancia. – stefaanv

+0

Hubiera pensado que el primer hilo que tocara la línea con la estática desencadenaría su creación/inicialización y que el segundo hilo que tocara esa línea sería plenamente consciente de esa creación e inicialización debido a cómo funciona la estática. ¿Por qué no sería ese el caso? –

0

Aparte de en un escenario de múltiples subprocesos - no. Bueno, déjeme calificar esto, la construcción es floja (por lo que la primera llamada puede tener un golpe) y la destrucción - bueno, no hay garantía (aparte de que será) en algún momento)

3

El inconveniente es que usted tiene no hay control sobre exactamente cuando se destruye el objeto. Esto será un problema si otros objetos estáticos intentan acceder a él desde sus destructores.

Un compilador compatible con C++ 11 debe implementar esto de una manera segura para hilos; sin embargo, los compiladores más antiguos podrían no hacerlo. Si tiene dudas, y no desea especialmente la inicialización diferida, puede forzar la creación del objeto llamando al descriptor de acceso antes de iniciar cualquier conversación.

+0

Entonces, ¿está diciendo que a pesar de que hay una función estática en esa función, en los compiladores que no son C++ 11 podría crearse de forma doble? pero mientras llame a la función de instancia antes de ingresar a mi fase de subprocesos múltiples del código, ¿es una creación segura de subprocesos? solo aclarando :) ¡Gracias por la respuesta hasta el momento! –

+0

@ w00te: Sí, eso es correcto. Antes de C++ 11, el estándar no tenía nada que decir acerca de la seguridad del hilo, por lo que dependía totalmente de la implementación del compilador si proteger contra la creación doble. Debe ser seguro para subprocesos con la mayoría de los compiladores razonablemente recientes. –

+0

+1 Gracias por la ayuda, es bueno saber que es una versión estándar específica. –

2

Hay dos cuestiones en la interfaz:

  • debe devolver una referencia
  • Usted debe hacer ya sea el destructor o el delete operador private

Además, hay un riesgo leve de intentar usar esta clase después de haber sido destruida.

En cuanto a sus preocupaciones de multi-threading (y la inicialización supongo): está bien en C++ 11 y han estado bien durante mucho tiempo en buenos compiladores de C++ de todos modos.

+0

+1 gracias por la ayuda :) –

0

En general, el calificador static para variable local en un método no garantiza que la variable se cree solo una vez. Si varios subprocesos llaman al método, podría crearse una vez para cada subproceso tantas veces como lo llamen muchos subprocesos. No se debe confundir con el miembro estático de la clase, que se crea una vez que se inicia el programa. La seguridad de subprocesos de variables estáticas locales depende de la realización particular de C++. Enlace útil: Are function static variables thread-safe in GCC?

Espero que ayude.

Cuestiones relacionadas