C++
Patrón de diseño Singleton
Buscar..
Observaciones
Un Singleton está diseñado para garantizar que una clase solo tenga una instancia y le brinde un punto de acceso global. Si solo necesita una instancia o un punto de acceso global conveniente, pero no ambos, considere otras opciones antes de pasar al singleton.
Las variables globales pueden hacer que sea más difícil razonar sobre el código. Por ejemplo, si una de las funciones de llamada no está contenta con los datos que recibe de un Singleton, ahora tiene que rastrear qué es lo que primero está dando los datos erróneos de Singleton en primer lugar.
Los singletons también fomentan el acoplamiento , un término usado para describir dos componentes del código que se unen, reduciendo así la medida de autocontención de cada componente.
Singletons no son compatibles con la concurrencia. Cuando una clase tiene un punto de acceso global, cada subproceso tiene la capacidad de acceder, lo que puede provocar puntos muertos y condiciones de carrera.
Por último, la inicialización perezosa puede causar problemas de rendimiento si se inicializa en el momento incorrecto. Eliminar la inicialización perezosa también elimina algunas de las características que hacen que Singleton sea interesante en primer lugar, como el polimorfismo (ver Subclases).
Fuentes: Patrones de programación de juegos por Robert Nystrom
Inicialización perezosa
Este ejemplo se ha extraído de la sección de Q & A
aquí: http://stackoverflow.com/a/1008289/3807729
Vea este artículo para un diseño simple para un perezoso evaluado con singleton de destrucción garantizada:
¿Puede alguien proporcionarme una muestra de Singleton en c ++?
El clásico perezoso evaluó y destruyó correctamente el singleton.
class S
{
public:
static S& getInstance()
{
static S instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return instance;
}
private:
S() {}; // Constructor? (the {} brackets) are needed here.
// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
S(S const&); // Don't Implement
void operator=(S const&); // Don't implement
// C++ 11
// =======
// We can use the better technique of deleting the methods
// we don't want.
public:
S(S const&) = delete;
void operator=(S const&) = delete;
// Note: Scott Meyers mentions in his Effective Modern
// C++ book, that deleted functions should generally
// be public as it results in better error messages
// due to the compilers behavior to check accessibility
// before deleted status
};
Consulte este artículo sobre cuándo usar un singleton: (no a menudo)
Singleton: ¿Cómo se debe utilizar?
Vea estos dos artículos sobre el orden de inicialización y cómo hacer frente:
Orden de inicialización de variables estáticas
Encontrar problemas de orden de inicialización estática de C ++
Vea este artículo que describe tiempos de vida:
¿Cuál es el tiempo de vida de una variable estática en una función de C ++?
Vea este artículo que discute algunas implicaciones de subprocesos para singletons:
Instancia Singleton declarada como variable estática del método GetInstance
Vea este artículo que explica por qué el bloqueo de doble comprobación no funcionará en C ++:
¿Cuáles son todas las conductas indefinidas comunes que un programador de C ++ debe conocer?
Subclases
class API
{
public:
static API& instance();
virtual ~API() {}
virtual const char* func1() = 0;
virtual void func2() = 0;
protected:
API() {}
API(const API&) = delete;
API& operator=(const API&) = delete;
};
class WindowsAPI : public API
{
public:
virtual const char* func1() override { /* Windows code */ }
virtual void func2() override { /* Windows code */ }
};
class LinuxAPI : public API
{
public:
virtual const char* func1() override { /* Linux code */ }
virtual void func2() override { /* Linux code */ }
};
API& API::instance() {
#if PLATFORM == WIN32
static WindowsAPI instance;
#elif PLATFORM = LINUX
static LinuxAPI instance;
#endif
return instance;
}
En este ejemplo, un simple conmutador de compilación vincula la clase API
a la subclase apropiada. De esta manera, se puede acceder a la API
sin estar acoplada a un código específico de la plataforma.
Hilo seguro Singeton
Los estándares C ++ 11 garantizan que la inicialización de los objetos de alcance de la función se inicialice de manera sincronizada. Esto se puede utilizar para implementar un singleton seguro para subprocesos con inicialización perezosa .
class Foo
{
public:
static Foo& instance()
{
static Foo inst;
return inst;
}
private:
Foo() {}
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
};
Desinticialización estática segura de singleton.
Hay veces con múltiples objetos estáticos en los que necesita poder garantizar que el singleton no se destruirá hasta que todos los objetos estáticos que usan el singleton ya no lo necesiten.
En este caso, std::shared_ptr
puede usarse para mantener el singleton activo para todos los usuarios, incluso cuando se llama a los destructores estáticos al final del programa:
class Singleton
{
public:
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
static std::shared_ptr<Singleton> instance()
{
static std::shared_ptr<Singleton> s{new Singleton};
return s;
}
private:
Singleton() {}
};
NOTA: Este ejemplo aparece como una respuesta en la sección de preguntas y respuestas aquí.