2008-11-18 28 views
9

Como dice el título. ¿Cómo crearía una instancia de una clase que esté disponible globalmente (por ejemplo, tengo un functor para imprimir y quiero tener una única instancia global de esto (aunque la posibilidad de crear más)).instancia global de una clase en C++

+0

Esta pregunta anterior es sólo un ejemplo de un producto único aquí en StackOverflow: http://stackoverflow.com/questions/270947/can-any-one-provide-me-a-sample-of-singleton-in-c –

Respuesta

17

Hacer todo el esfuerzo de hacer que un objeto singleton utilizando el patrón habitual no aborde la segunda parte de su pregunta, la posibilidad de hacer más si es necesario. El "patrón" singleton es muy restrictivo y no es más que una variable global con otro nombre.

// myclass.h 

class MyClass { 
public: 
    MyClass(); 
    void foo(); 
    // ... 
}; 

extern MyClass g_MyClassInstance; 

// myclass.cpp 

MyClass g_MyClassInstance; 

MyClass::MyClass() 
{ 
    // ... 
} 

Ahora, en cualquier otro módulo basta con incluir myclass.h y utilizar g_MyClassInstance como de costumbre. Si necesita hacer más, hay un constructor listo para llamar.

+0

Ugh. Esto se romperá si MyClass depende de alguna otra instancia global que se inicialice primero, ya que el orden de inicialización de los globales es "aleatorio". Es mejor usar clase de fábrica de clase regular + (crear una sola instancia). – richq

+0

@rq: No es aleatorio: vea http://stackoverflow.com/questions/294270/how-do-you-call-a-constructor-for-global-objects-for-arrays-of-objects-and-for # 294308 –

+0

Aleatorio, indefinido, no se puede determinar en tiempo de compilación ... misma diferencia. – richq

1

Como una ligera modificación en el patrón singleton, si también desea permitir la posibilidad de crear más instancias con distintas duraciones, simplemente haga que ctors, dtor y operator = public sean públicos. De esta forma, obtienes la única instancia global a través de GetInstance, pero también puedes declarar otras variables en el montón o la pila del mismo tipo.

La idea básica es el patrón singleton, sin embargo.

1

La implementación más sencilla y segura de concurrencia es singleton de Scott Meyer:


#include <iostream> 

class MySingleton { 
public: 
    static MySingleton& Instance() { 
     static MySingleton singleton; 
     return singleton; 
    } 
    void HelloWorld() { std::cout << "Hello World!\n"; } 
}; 

int main() { 
    MySingleton::Instance().HelloWorld(); 
} 

Ver tema IV here para un análisis de John Vlissides (de la fama GoF).

+0

NO ES concurrencia segura. En C++ estándar, la estática se "inicializa" cuando el constructor finaliza, por lo que cada hilo que ingrese al método Instance() en el momento de la inicialización causará la recreación del singleton, –

+0

Dmitry Khalatov @ Técnicamente correcto. Hay varias soluciones simples. a) Use gcc tiene una solución explícita para tratar esto (no estándar). b) Cree el objeto antes de cualquier subproceso c) Use un candado dentro del método Instance(). –

+0

Estoy de acuerdo con @Dmitry: hasta que el estándar proporcione una forma de manejar la presencia de hilos, no es seguro. – xtofl

3

En primer lugar el hecho de que desea variables globales es un 'olor código' (como por Martin Fowler).

Pero para lograr el efecto que desee puede usar una variación del Singleton.
Usar variables de funciones estáticas. Esto significa que la variable no se crea hasta que se use (esto le da una evaluación perezosa) y todas las variables se destruirán en el orden inverso de creación (por lo que esto garantiza que se usará el destructor).

class MyVar 
{ 
    public: 
     static MyVar& getGlobal1() 
     { 
      static MyVar global1; 
      return global1; 
     } 
     static MyVar& getGlobal2() 
     { 
      static MyVar global2; 
      return global2; 
     } 
     // .. etc 
} 
+3

De acuerdo con esta lógica, std :: cout también es un olor a código. –

+0

@ rr-: Debería leer [libro de "Fowlers de Martin" sobre refactorización] (http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/ref=sr_1_1?ie=UTF8&qid= 1439219908 & sr = 8-1 & keywords = refactoring + by + martin + fowler). –

+0

@ rr-: O cualquiera de los millones de artículos sobre [El estado mutable global es malo] (http://programmers.stackexchange.com/questions/148108/why-is-global-state-so-evil) –

0

Prefiero permitir un singleton pero no aplicarlo así que en nunca ocultar los constructores y destructores. Eso ya se había dicho solo dando mi apoyo.

Mi error es que no uso a menudo el uso de una función de miembro estático a menos que quiera crear un singleton verdadero y ocultar el constr.Mi enfoque habitual es este:

template< typename T > 
T& singleton(void) 
{ 
    static char buffer[sizeof(T)]; 
    static T* single = new(buffer)T; 
    return *single; 
} 

Foo& instance = singleton<Foo>(); 

¿Por qué no utilizar una instancia estática de T en lugar de una ubicación nueva? La instancia estática le da a la orden de construcción garantías, pero no orden de destrucción. La mayoría de los objetos se destruyen en orden inverso de construcción, pero variables estáticas y globales. Si usa la versión estática de la instancia, eventualmente obtendrá segfaults misteriosos/intermitentes, etc. después del final de main.

Esto significa que nunca se llamará al destructor singletons. Sin embargo, el proceso para bajar de todos modos y los recursos serán reclamados. Es algo difícil de acostumbrar, pero créeme que no hay una mejor solución de plataforma cruzada en este momento. Afortunadamente, C++ 0x ha realizado cambios para garantizar el orden de destrucción que solucionará este problema. Una vez que el compilador admite el nuevo estándar, simplemente actualice la función singleton para usar una instancia estática.

También, en el implemenation real utilizo impulso para conseguir la memoria alineados en lugar de una matriz de caracteres sin formato, pero no quería complicar el ejemplo

Cuestiones relacionadas