2009-03-11 39 views
5

En C++, supongamos que quiere declarar una variable global para ser utilizada por muchos. ¿Cómo lo haces?¿Cuál es la mejor manera de declarar una variable global?

Comúnmente declaro y defino en un archivo cpp, y luego uso extern en otro archivo cpp (y no en los encabezados).

No me gusta este enfoque, y estoy pensando en algo como lo siguiente:

En un archivo de cabecera:

some_file.h

Class MYGlobalClass 
{ 

}; 


MyGlobalClass& MyGlobalClassInstance() 
{ 
    static MYGlobalClass instance; 
    return instance; 

} 

Editar

Considere en los siguientes contextos:

  • se pueden utilizar en aplicaciones de subprocesos múltiples
  • contaminación espacio de nombres
  • NO puede necessery ser un producto único, ya que muchos ejemplos de esto podrían ser creados

¿Cuáles son sus pensamientos, sugerencias, nuevas ideas?

+0

Patrón de diseño Singleton –

+0

No es una buena idea, consulte los comentarios a continuación –

+0

¿Una variable global, de la que desea crear varias instancias? Parece que todavía necesita elaborar un poco ... – Reunanen

Respuesta

2

declararlo en un fichero de cabecera (usando extern), y lo definen en (o lo que sea otra extensión) archivo uno.cpp. Puede usar una función y devolver una referencia a una variable estática como la que mostró para evitar problemas con el orden de construcción en relación con otras variables de ámbito de espacio de nombres similares en otros archivos .cpp. Pero recuerde que eso no lo protegerá de los problemas de orden de destrucción, que es exactamente el orden inverso al de la construcción (estas cosas se llaman "fiasco de orden de inicialización estática". Si usa una función como la suya y la coloca en los encabezados, hágalo en línea para hacer que la redefinición de la función sea válida cuando se incluye en múltiples archivos .cpp (lógicamente, la función solo es aparente una vez, porque la estática solo existirá una vez, no por separado para cada archivo en el que se incluye). declararlo en un encabezado pero definirlo en un archivo.cpp (pero luego, elimine el en línea de él!).

inline A& getA() { static A a; return a; } 

Los problemas potenciales con el fin destrucción pueden ser evitados mediante el uso de new:

inline A& getA() { static A *a = new A; return *a; } 

El destructor de la misma, sin embargo, nunca serán llamados a continuación. Si necesita seguridad de subprocesos, debe agregar un mutex que proteja contra accesos múltiples. boost.thread probablemente tiene algo para eso.

+0

¿cuál es el problema con la orden de destrucción? – yesraaj

+0

es el orden inverso exacto de construcción. es decir, si se crea un objeto antes de llamar a getA() la primera vez, se destruirá después del objeto en getA(). Es decir, hay un orden en particular. Si, por ejemplo, accede a getA() en el destructor de objetos, accederá a una referencia colgante. –

+0

busque "fiasco de orden de inicialización estática" y creo que encontrará bastantes explicaciones (más extensas que mi breve descripción aquí, por supuesto) de esa rareza. –

0

extern MyGlobalClass MyGlobalClassInstance;

Editar: No estática>. <

+0

estática no funcionarán, tengo que compartirla entre archivos, módulos o incluso bibliotecas. gracias por su tiempo aunque –

4

declarar como extern en un fichero de cabecera incluidos por "muchos" y definirlo en un archivo * .cpp

+0

¡Buena idea! quizás definir una función en línea en el archivo de encabezado? e incluir el encabezado por muchos? –

+0

No hay escuela como la vieja escuela. – chaos

1

declarar y definir en el archivo CPP

Mantenga la declaración extern -ed en un encabezado. Defínelo solo una vez en un archivo de implementación.

Estás cerca. Use un espacio de nombres en su lugar para las variables globales.

namespace myns { 
    int foo = 0; 
} 

Ahora, si se trata de un objeto de clase, que están mirando el patrón Singletion. De hecho, su código de muestra refleja un diseño de Singleton. Sin embargo, si va a definir la función en el encabezado, hágalo en línea - De lo contrario, violación de ODR.

+0

He considerado el espacio de nombres .... –

+0

Estás pensando en un objeto Singleton. En ese caso, tenga un accesorio y úselo. Por supuesto, aún necesita incluir el encabezado. Eche un vistazo.http: //en.wikipedia.org/wiki/Singleton_pattern – dirkgently

+0

Gracias, estoy familiarizado con Singleton. Sin embargo, NO es la solución que estoy buscando. –

-1

¿Por qué no utilizar un buen patrón singleton antiguo?

+0

Porque solo agrega nuevos problemas, y no resuelve el que necesita resuelto – jalf

+0

¡No quiero solo una instancia de esa clase! más una sobrecarga innecesaria –

+0

¡Pero el código que ha escrito es un singleton con exactamente una instancia estática! –

2

Su idea de una estática dentro de la función de acceso es significativamente diferente de una variable global. La diferencia es cuando se construye, y es más probable que sea un problema importante con múltiples hilos. ¿Qué pasa si dos hilos llaman al MyGlobalClassInstance al mismo tiempo? Dependiendo del entorno, pero sospecho que esto es típico de la mayoría de los compiladores de C++, es posible que reciba dos llamadas al constructor de MyGlobalClass ejecutándose al mismo tiempo, dirigiéndose a la misma área de memoria.

Si tiene un subproceso único, es menos probable que sea un problema.

Si declara la instancia como un miembro estático normal o como una variable global normal en el archivo fuente, probablemente le sea más fácil, porque se llamará al constructor antes de que se ejecute main, antes de que tenga la oportunidad de comenzar otros hilos.

+0

Por otro lado, si declara una variable global simple, obtendrá todos los problemas con un orden de inicialización impredecible. – jalf

+0

Sí. ¿No es C++ una perra? :) –

+0

yep :) (10 caracteres de relleno) – jalf

1

Es Es realmente una variable global que teóricamente se podría acceder externamente por cualquier módulo, se debe poner la declaración externa en el archivo de cabecera:

// MyClass.h 
class MyClass { ... }; 
extern MyClass myGlobalInstance; 

// MyClass.cpp 
MyClass myGlobalInstance; 

Si es sólo un objeto global que realmente debe ser accesible únicamente por un solo módulo, limite su alcance haciéndolo una variable de clase estática privada (o protegida), una variable de función estática (si solo la necesita una función) o en un espacio de nombre anónimo:

Opción 1:

// MyClass.h 
class MyClass 
{ 
private: // or protected, if you want it accessible by subclasses 
    static MyClass myGlobalInstance; 
}; 

Opción 2:

// MyClass.cpp 
void someFunction() 
{ 
    // it's global, but only accessible inside this function 
    static MyClass myGlobalInstance; 
    ... 
} 

Opción 3:

// MyClass.cpp 
namespace 
{ 
    MyClass myGlobalInstance; 
} 

// it's now only accessible in this file 
10

El mejor consejo es, probablemente, "tratar de evitar globales". La gente no necesita variables globales tan a menudo como piensan. Por lo general, resulta que "pasar todo como argumentos a los constructores" no es tanto trabajo como las personas piensan cuando escuchan la sugerencia. También tiende a conducir a un código más limpio con menos dependencias y más explícitas.

No conozco ninguna forma "correcta" de declarar globales en C++. La forma en que lo haces ahora funciona bien, pero el orden de inicialización no está especificado, por lo que si hay alguna dependencia entre tus globales, estás en problemas.

Una función que devuelve una instancia estática más o menos resuelve ese problema, pero no es segura para subprocesos.

Y un singleton es simplemente una idea terrible. No resuelve tu problema, pero agrega restricciones adicionales a tu código, que en realidad no eran necesarias, y es muy probable que vuelvan y te muerdan más tarde.

Cuestiones relacionadas