C ++ singleton vs. objeto estático global

Un amigo mío hoy me preguntó por qué prefería usar singleton sobre un objeto estático global. La forma en que lo comencé a explicar fue que el singleton puede tener estado vs. objeto estático global no … pero no estaba seguro … porque esto en C ++ … (venía de C #)

¿Cuáles son las ventajas una sobre la otra? (en C ++)

En realidad, en C ++ la forma preferida es el objeto estático local.

Printer & thePrinter() { static Printer printer; return printer; } 

Sin embargo, esto es técnicamente un singleton, esta función incluso puede ser un método estático de una clase. Por lo tanto, se garantiza que se construirá antes que se use a diferencia de los objetos estáticos globales, que se pueden crear en cualquier orden, lo que hace posible que falle de forma inconsistente cuando un objeto global usa otro escenario bastante común.

Lo que lo hace mejor que una forma común de hacer singletons al crear una instancia nueva al invocar new es que se llamará al destructor de objetos al final de un progtwig. No sucederá con singleton dinámicamente asignado.

Otro aspecto positivo es que no hay forma de acceder a singleton antes de que se cree, incluso desde otros métodos estáticos o desde subclases. Le ahorra tiempo de depuración.

En C ++, el orden de instanciación de objetos estáticos en diferentes unidades de comstackción no está definido. Por lo tanto, es posible que un mundo haga referencia a otro que no está construido, haciendo explotar su progtwig. El patrón singleton elimina este problema al vincular la construcción a una función miembro estática o función libre.

Hay un resumen decente aquí .

Un amigo mío hoy me preguntó por qué prefería usar singleton sobre un objeto estático global. La forma en que lo comencé a explicar fue que el singleton puede tener estado vs. objeto estático global no … pero no estaba seguro … porque esto en C ++ … (venía de C #)

Un objeto global estático también puede tener estado en C #:

 class myclass { // can have state // ... public static myclass m = new myclass(); // globally accessible static instance, which can have state } 

¿Cuáles son las ventajas una sobre la otra? (en C ++)

Un singleton paraliza su código, una instancia estática global no lo hace. Hay innumerables preguntas sobre SO sobre los problemas con los singletons. Aquí hay uno , y otro , u otro .

En resumen, un singleton te da dos cosas:

  • un objeto accesible a nivel mundial, y
  • una garantía de que solo se puede crear una instancia.

Si queremos solo el primer punto, debemos crear un objeto accesible a nivel mundial. ¿ Y por qué querríamos el segundo? No sabemos de antemano cómo se puede usar nuestro código en el futuro, entonces ¿por qué bloquearlo y eliminar lo que puede ser una funcionalidad útil? Por lo general, nos equivocamos cuando predecimos que “solo necesitaré una instancia”. Y hay una gran diferencia entre “Solo necesitaré una instancia” (la respuesta correcta es crear una instancia) y “la aplicación no se puede ejecutar bajo ninguna circunstancia si se crea más de una instancia. Se bloqueará, formatee el disco duro del usuario y publique datos confidenciales en Internet “(la respuesta aquí es: lo más probable es que su aplicación esté rota, pero si no es así, entonces sí, lo único que necesita es un singleton)

Razón 1:
Los singletons son fáciles de hacer, por lo que son de fabricación perezosa.
Si bien puede hacer esto con globales, requiere un trabajo adicional por parte del desarrollador. Entonces, por defecto, los globales siempre se inicializan (aparte de algunas reglas especiales con espacios de nombres).

Entonces, si su objeto es grande y / o costoso de construir, es posible que no desee construirlo a menos que realmente tenga que usarlo.

Razón 2:
Orden del problema de inicialización (y destrucción).

 GlobalRes& getGlobalRes() { static GlobalRes instance; // Lazily initialized. return instance; } GlobalResTwo& getGlobalResTwo() { static GlobalResTwo instance; // Lazy again. return instance; } // Order of destruction problem. // The destructor of this object uses another global object so // the order of destruction is important. class GlobalResTwo { public: GlobalResTwo() { getGlobalRes(); // At this point globalRes is fully initialized. // Because it is fully initialized before this object it will be destroyed // after this object is destroyed (Guaranteed) } ~GlobalResTwo() { // It is safe to use globalRes because we know it will not be destroyed // before this object. getGlobalRes().doStuff(); } }; 

Otro beneficio de Singleton sobre el objeto estático global es que, debido a que el constructor es privado, existe una directiva muy clara, que impone el comstackdor, que dice “Solo puede haber uno”.

En comparación, con el objeto estático global, no habrá nada que detenga la creación de un código de desarrollador que cree una instancia adicional de este objeto.

El beneficio de la restricción adicional es que tiene una garantía de cómo se usará el objeto.

Usando la expresión idiomática Singleton (“construir en el primer uso”), puede evitar el fiasco de orden de inicialización estática

En C ++, no hay una gran diferencia entre los dos en términos de utilidad real. Un objeto global puede, por supuesto, mantener su propio estado (posiblemente con otras variables globales, aunque no lo recomiendo). Si va a utilizar un global o un singleton (y existen muchas razones para no hacerlo), la razón principal para usar un singleton sobre un objeto global es que con un singleton, puede tener un polymorphism dynamic al heredar varias clases de una clase base singleton.

OK, hay dos razones para ir con un singleton realmente. Una es el orden estático de lo que todos hablan.

La otra es evitar que alguien haga algo como esto al usar tu código:

 CoolThing blah; gs_coolGlobalStaticThing = blah; 

o, peor aún:

 gs_coolGlobalStaticThing = {}; 

El aspecto de la encapsulación protegerá su instancia de idiotas y jerks maliciosos.