visual studio que plantilla patrón explicacion ejemplos desventajas con c++ class static singleton

c++ - studio - singleton java explicacion



C++ singleton vs objeto completamente estático (5)

Digamos que necesitamos tener solo una instancia de alguna clase en nuestro proyecto. Hay dos maneras de hacerlo.

Quiero comparar. Por favor, puede revisar mi comprensión.

1) Patrón Singleton clásico

2) Clase completamente estática (todos los métodos y miembros son estáticos).


Según entiendo las diferencias son las siguientes:

a) El orden de inicialización de los miembros estáticos en diferentes unidades no está definido. Por lo tanto, la inicialización de miembros completamente estática no puede usar miembros / funciones estáticas de otros módulos. Y Singleton no tiene este problema.

b) Tenemos que lidiar con los hilos para getInstance () de Singleton. Sin embargo, la clase completamente estática no tiene este problema.

c) El acceso a los métodos se ve un poco diferente. Foo :: bar (); vs Foo :: getInstance () -> bar (); Generalmente, singleton puede devolver NULL para identificar que hubo algunos problemas con la construcción del objeto y la clase estática no puede.

d) La definición de clase se ve un poco torpe con un montón de estadísticas para la clase estática.

¿Me he perdido algo?


Digamos que necesitamos tener solo una instancia de alguna clase en nuestro proyecto. Hay dos maneras de hacerlo.

Una mejor solución:

Una variable en main que pase como parámetro a todas las funciones requeridas sería otra.

a) El orden de inicialización de los miembros estáticos en diferentes unidades no está definido. Por lo tanto, la inicialización de miembros completamente estática no puede usar miembros / funciones estáticas de otros módulos. Y Singleton no tiene este problema.

Los Singletons tienen este problema si su constructor / destructor accede a otra variable de vida estática global.

b) Tenemos que lidiar con los hilos para getInstance () de Sigleton. Sin embargo, la clase completamente estática no tiene este problema.

No es realmente un problema, ¿verdad? Si está al tanto, simplemente agregue los bloqueos apropiados en el código.

c) El acceso a los métodos se ve un poco diferente. Foo :: bar (); vs Foo :: getInstance () -> bar (); Generalmente, sigleton puede devolver NULL para identificar que hubo algunos problemas con la construcción del objeto y la clase estática no puede.

Haría que mi getInstance () devuelva una referencia. Entonces no hay ambigüedad si el puntero es NULL. Funcionó o lanzó una excepción. Además, esto conduce a un diseño en el que la destrucción es correcta en la instancia (no tome esto como un consejo para usar Singleton, lo evitaría si fuera posible (pero si lo hace, hágalo limpio)).

d) La definición de clase se ve un poco torpe con un montón de estadísticas para la clase estática.

No es más estúpido que escribir un singleton correctamente.

El problema con ambos métodos es que ambos acceden global mutable state y, por lo tanto, el uso de estos objetos de "instancia única" por otros objetos está oculto para el usuario. Esto puede llevar a problemas con las pruebas (TDD requiere la capacidad de simular una funcionalidad externa, pero global mutable state evita que la capacidad del probador se burle de las dependencias externas (fácilmente)).

Cualquier objeto que no sea POD tiene un constructor que puede potencialmente lanzar una excepción. Por lo tanto, para los objetos en el espacio de nombres global, esto significa que se pueden lanzar excepciones antes de que se ingrese a main () (esto puede llevar a errores difíciles de encontrar (si tiene muchos objetos globales (tiene que poner puntos de interrupción en todas partes)). el mismo problema existe con un singleton que se evalúa perezosamente; si en el primer uso se lanza, ¿cómo se corrige para que no se lance un intento posterior? ¿Su aplicación continuará lanzándose cada vez que se recupere el singleton?


Otra opción que se pasa por alto es el namespace de namespace .

namespace xyz { namespace { int private_variable; } int get_pv() { return private_variable; } }

Funcionalmente, esto va a ser similar a tu opción # 2, pero no puedes "eliminar" accidentalmente esta cosa. No puedes crear accidentalmente una instancia de ello. Es solo una recopilación de datos y funciones relacionadas globalmente accesibles. Puedes (como en mi ejemplo) incluso tener miembros y funciones "privados".

Por supuesto el uso sería algo como esto:

int x = xyz::get_pv();


También puede usar el patrón Borg, que es un poco más complicado en C ++ a menos que tenga acceso a una clase de puntero compartida. La idea es que se puede crear una instancia de cualquier número de clases Borg, pero su estado se comparte en todas las instancias.


Usted podría agregar: los objetos estáticos pueden lanzar excepciones. El ejecutable no se iniciará y es difícil depurar / manejar bien.


Ya sea que lo llames Singleton o Monostate o cualquier nombre de fantasía ... la naturaleza muy molesta de esto es que tienes UNA instancia del objeto y muchos le escriben: las variables globales, cualquiera que sea su forma, son malas .

La idea de que necesita una instancia única es generalmente torpe. La mayoría de las veces lo que realmente necesita son partes que se comunican y comparten la misma instancia. Pero otro grupo de partes podría perfectamente usar otra instancia sin problema.

Cualquier código que afirme necesitar una variable global es altamente sospechoso. Puede parecer más sencillo usar uno, pero seamos realistas, usted podría pasar el objeto a todas y cada una de las funciones, complicaría su firma pero funcionaría de todos modos.

Sin embargo, lo admito, parece más sencillo usar variables globales ... hasta que note los problemas:

  • multihilo está comprometido
  • La capacidad de prueba se reduce, ya que una prueba puede afectar a la siguiente.
  • el análisis de dependencia es extremadamente complicado: es difícil saber en qué estado depende su método cuando se introduce globalmente dentro de los submétodos ...

Ahora, en lo que respecta a singleton, la creación de subprocesos múltiples no se puede usar en C ++ antes de C ++ 0x (cuando es posible usar locales estáticos), por lo tanto, es necesario crearlo en un solo hilo y retrasar el acceso antes: crear una instancia en main , es tu mejor apuesta.

La destrucción puede causar un caos ya que la vida de Singleton / Static puede terminar antes de que otros terminen con ella, y luego es un comportamiento indefinido. Esto es típico de un Singleton Logger . La estrategia habitual es filtrar descaradamente ...

Después de eso, si aún quieres uno, te deseo buena suerte, eso es todo lo que esta comunidad puede hacer por ti.