2010-09-08 18 views
14

Quiero declarar constantes de cadena que se utilizarán en varias clases en el proyecto. Estoy considerando dos alternativasconstantes de cadena estática en clase vs espacio de nombres para constantes [C++]

Opción 1:

#header file 
class constants{ 
    static const string const1; 
}; 

#cpp file 

const string constants::const1="blah"; 

Opción 2:

#header file 
namespace constants{ 
    static const string const1="blah"; 
}; 

Sólo me preguntaba lo que sería una mejor aplicación.

Ya miraron

Where to store Class Specific named constants in C++

Where to put constant strings in C++: static class members or anonymous namespaces


UPDATE:

Opción 3:

Basado en las sugerencias de "potatoswatter" y "sellibitze" actualmente tengo la siguiente implementación?

#header file 
namespace constants{ 
    extern const string& const1(); //WORKS WITHOUT THE EXTERN ***WHY*** 
}; 

#cpp file 
namespace constants{ 
    const string& const1(){static string* str = new string ("blah"); return *str;} 
} 

Estoy incluyendo el archivo de encabezado donde necesito usar las constantes. ¿Hay algún inconveniente importante de esta implementación?

+0

La opción 2 no parece ser una solución. Las cadenas aún se definirán por separado para cada archivo fuente, a pesar de aparecer en el mismo espacio de nombres. – Potatoswatter

+4

La opción 2 es una solución si Shishya en realidad obtiene la sintaxis correcta. (No 'static', y la cadena solo se puede declarar en el encabezado, pero será necesario definirla en un archivo fuente). – pkh

+0

@pkh: la sintaxis es un poco más complicada que eso; v) – Potatoswatter

Respuesta

9

Actualización 2 años más tarde:

Cada accesibles mundial por más de un archivo de origen debe ser envuelto en una función inline por lo que las acciones de engarce el objeto entre los archivos y el programa inicializa correctamente.

inline std::string const &const1 { 
    static std::string ret = "hello, world!"; 
    return ret; 
} 

La función inline es implícitamente extern y se puede envolver en un espacio de nombres con nombre o una clase, si lo desea. (Pero no use una clase solo para contener miembros estáticos, ya que los espacios de nombres son mejores para eso. Y no use un espacio de nombre anónimo ya que eso vencería al enlazador, y cada fuente vería un objeto diferente std::string.)

+0

Será más limpio en presencia de constantes múltiples para usar las constantes del espacio de nombres {...} en el archivo fuente. – pkh

+0

@Potatoswatter: $ 2.13.4/2- Si todos los literales de cadena son distintos (es decir, se almacenan en objetos no superpuestos) se define la implementación. El efecto de intentar modificar un literal de cadena no está definido. Entonces, incluso si se definen por separado, es posible que no ocupen realmente tanto espacio en la memoria si esa era la preocupación. – Chubsdad

+0

@Chubsdad: los únicos literales de cadena en el código de OP son los inicializadores de 'std :: string'. Me refería a los objetos 'std :: string'. – Potatoswatter

4

Opción 1 logra lo mismo que la Opción 2, pero de una manera más desordenada.

Si va a utilizar una clase que solo tiene miembros estáticos, especialmente para acceso/constantes globales, use un espacio de nombres.

4

Ninguno. Me quedo con esto:

// header file 
namespace constants { 
extern const char const1[]; 
} 

// cpp file 
namespace constants { 
extern const char const1[] = "blah"; 
} 

El archivo de cabecera contiene una declaración de const1 con el tipo incompleto, pero convertible en char const* y el CPP-archivo contiene una definición de la matriz de caracteres con enlace externo. No hay inicialización dinámica como la que tiene con std::string. Entonces, eso es una ventaja, en mi humilde opinión.

+0

¿No debería el código en .cpp ser esto en su lugar? 'const char constants :: const1 [] =" blah ";', es decir: no 'extern' y no' namespace' redeclaration. –

+0

@Remy: * encogerse de hombros *. Haz lo que quieras. Pero no hay nada malo con el código que publiqué. Puede eliminar 'extern' en el archivo cpp si incluye el encabezado que ya declara' const1' para tener un enlace externo. Pero como en C++ las variables constantes en el ámbito del espacio de nombres tienen un enlace interno por defecto, necesita tener al menos un 'extern' allí. Lo que publique también funciona sin incluir el encabezado en el archivo cpp, por cierto. – sellibitze

7

Todas las respuestas que recurren a std::string corren el riesgo de asignar dinámicamente memoria para una cadena literal que se mantendrá constante durante toda la vida del programa (y el binario), por lo que deben evitarse.

sellibitze La respuesta se acerca, pero tiene el problema de declararla una vez y luego definirla en otro lugar, lo cual no me parece elegante y es más trabajo. La mejor manera sería

namespace constants { 
    const char * const blah = "blah!" 
    const char * const yada = "yada yada!" 
} 

Esta solución es se discute más here.