ventajas usar patron ejercicios desventajas cuando conexion c++ design-patterns c++11 singleton

c++ - usar - ¿Cómo es la implementación de un Singleton de Meyers en Singleton?



singleton c# (2)

Este es un singleton porque static duración del almacenamiento static para una función local significa que solo existe una instancia de ese local en el programa.

Debajo del capó, esto se puede considerar aproximadamente equivalente al siguiente C ++ 98 (e incluso podría ser implementado vagamente de esta manera por un compilador):

static bool __guard = false; static char __storage[sizeof(Singleton)]; // also align it Singleton& Instance() { if (!__guard ) { __guard = true; new (__storage) Singleton(); } return *reinterpret_cast<Singleton*>(__storage); } // called automatically when the process exits void __destruct() { if (__guard) reinterpret_cast<Singleton*>(__storage)->~Singleton(); }

Los bits de seguridad del hilo hacen que sea un poco más complicado, pero es esencialmente lo mismo.

En cuanto a una implementación real para C ++ 11, hay una variable de protección para cada elemento estático (como el booleano anterior), que también se utiliza para las barreras y los subprocesos. Mire la salida AMD64 de Clang para:

Singleton& instance() { static Singleton instance; return instance; }

El ensamblaje AMD64, por instance del Clang 3.0 de Ubuntu en AMD64 en -O1 (cortesía de http://gcc.godbolt.org/ es:

instance(): # @instance() pushq %rbp movq %rsp, %rbp movb guard variable for instance()::instance(%rip), %al testb %al, %al jne .LBB0_3 movl guard variable for instance()::instance, %edi callq __cxa_guard_acquire testl %eax, %eax je .LBB0_3 movl instance()::instance, %edi callq Singleton::Singleton() movl guard variable for instance()::instance, %edi callq __cxa_guard_release .LBB0_3: movl instance()::instance, %eax popq %rbp ret

Puede ver que hace referencia a un guardia global para ver si se requiere inicialización, usa __cxa_guard_acquire , prueba la inicialización nuevamente, y así sucesivamente. Exactamente en casi todos los sentidos, como la versión que publicó en Wikipedia, excepto que usa el ensamblaje AMD64 y los símbolos / diseño especificados en Itanium ABI .

Tenga en cuenta que si ejecuta esa prueba, debe darle a Singleton un constructor no trivial para que no sea un POD, de lo contrario, el optimizador se dará cuenta de que no tiene sentido hacer todo el trabajo de protección / bloqueo.

He estado leyendo mucho sobre Singletons, cuándo deberían y no deberían usarse, y cómo implementarlos de manera segura. Estoy escribiendo en C ++ 11, y me he topado con la implementación inicializada de Meyer de un singleton, como se ve en esta pregunta.

Esta implementación es:

static Singleton& instance() { static Singleton s; return s; }

Entiendo que esto es seguro para hilos de otras preguntas aquí en SO, pero lo que no entiendo es cómo esto es en realidad un patrón singleton. He implementado singletons en otros idiomas, y estos siempre terminan algo así como este ejemplo de Wikipedia :

public class SingletonDemo { private static volatile SingletonDemo instance = null; private SingletonDemo() { } public static SingletonDemo getInstance() { if (instance == null) { synchronized (SingletonDemo .class){ if (instance == null) { instance = new SingletonDemo (); } } } return instance; } }

Cuando miro este segundo ejemplo, es muy intuitivo cómo es un singleton, ya que la clase contiene una referencia a una instancia de sí mismo, y solo devuelve esa instancia. Sin embargo, en el primer ejemplo, no entiendo cómo esto evita que existan dos instancias del objeto. Entonces mis preguntas son:

  1. ¿Cómo aplica la primera implementación un patrón singleton? Supongo que tiene que ver con la palabra clave estática, pero espero que alguien me explique en profundidad lo que sucede debajo del capó.
  2. Entre estos dos estilos de implementación, ¿es preferible uno sobre el otro? ¿Cuáles son los pros y los contras?

Gracias por cualquier ayuda,


// Singleton.hpp class Singleton { public: static Singleton& Instance() { static Singleton S; return S; } private: Singleton(); ~Singleton(); };

Esta implementación se conoce como Singleton de Meyers. Scott Meyers dice:

"Este enfoque se basa en la garantía de C ++ de que los objetos estáticos locales se inicializan cuando la definición del objeto se encuentra por primera vez durante una llamada a esa función". ... "Como beneficio adicional, si nunca llamas a una función que emula un objeto estático no local, nunca incurres en el costo de construir y destruir el objeto".

Cuando llama a Singleton& s=Singleton::Instance() primera vez, se crea el objeto y cada llamada siguiente a Singleton::Instance() da como resultado el mismo objeto que se devuelve. Tema principal:

Otra implementación se llama Singleton con fugas de confianza.

class Singleton { public: static Singleton& Instance() { if (I == nullptr) { I = new Singleton(); } return *I; } private: Singleton(); ~Singleton(); static Singleton* I; }; // Singleton.cpp Singleton* Singleton::I = 0;

Dos problemas:

  • fugas, a menos que implemente un lanzamiento y asegúrese de llamarlo (una vez)
  • no es seguro