c++ - que - using namespace std error
¿Por qué se utilizan espacios de nombres sin nombre y cuáles son sus beneficios? (6)
Acabo de unirme a un nuevo proyecto de software C ++ y estoy intentando comprender el diseño. El proyecto hace uso frecuente de espacios de nombres sin nombre. Por ejemplo, algo como esto puede ocurrir en un archivo de definición de clase:
// newusertype.cc
namespace {
const int SIZE_OF_ARRAY_X;
const int SIZE_OF_ARRAY_Y;
bool getState(userType*,otherUserType*);
}
newusertype::newusertype(...) {...
¿Cuáles son las consideraciones de diseño que pueden causar que uno use un espacio de nombre sin nombre? ¿Cuáles son las ventajas y desventajas?
(En lo que sigue, las cosas atrapadas son cosas que ya no se aplican a C ++ 11, pero se aplicaron a C ++ 03. C ++ 11 ya casi no hace diferencias (si las hay, solo son lenguaje) diferencias de abogado que no recuerdo).
Espacios de nombre sin nombre son una utilidad para hacer que un identificador efectivamente unidad de traducción local. Se comportan como si eligiera un nombre único por unidad de traducción para un espacio de nombres:
namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }
El paso adicional que usa el cuerpo vacío es importante, por lo que ya puede referir dentro del cuerpo del espacio de nombres a identificadores como ::name
que están definidos en ese espacio de nombres, ya que la directiva using ya se realizó.
Esto significa que puede tener funciones gratuitas llamadas (por ejemplo) help
que pueden existir en varias unidades de traducción, y no entrarán en conflicto en el momento del enlace, ya que todas tienen un nombre único debido a su espacio de nombre único en el que se encuentran . El efecto es casi idéntico al uso de la palabra clave static
utilizada en C que puede incluir en la declaración de identificadores. espacios de nombres no nombrados son una alternativa superior, pudiendo incluso hacer que una unidad de traducción de tipo sea local. static
uso de static
de esa manera está obsoleto en C ++, ya que los
namespace { int a1; }
static int a2;
Ambas son una unidad de traducción local y no entrarán en conflicto en el momento del enlace. Pero la diferencia es que el a1
en el espacio de nombres anónimo solo obtiene un nombre único. Todavía tiene un enlace externo y puede exportarse a la tabla de símbolos del archivo objeto que se está creando. Esto se vuelve importante si desea usar su dirección como un argumento de plantilla:
template<int * ptr> struct sample { };
// OK - a1 has external linkage
sample<&a1> s1;
// NOT OK - translation unit locality is done by giving a2 internal linkage.
sample<&a2> s2;
Los parámetros de plantilla tienen que tener un enlace externo, por lo que en este caso el identificador debe colocarse en un espacio de nombre anónimo.
Lea el excelente artículo en comeau-computing `¿Por qué se usa un espacio de nombre sin nombre en lugar de estático? .
Además de las otras respuestas a esta pregunta, usar un espacio de nombre anónimo también puede mejorar el rendimiento. Como los símbolos dentro del espacio de nombres no necesitan ningún enlace externo, el compilador es más libre para realizar una optimización agresiva del código dentro del espacio de nombres. Por ejemplo, una función que se llama varias veces una vez en un bucle se puede insertar sin impacto en el tamaño del código.
Por ejemplo, en mi sistema el siguiente código toma alrededor del 70% del tiempo de ejecución si se usa el espacio de nombres anónimo (x86-64 gcc-4.6.3 y -O2; tenga en cuenta que el código adicional en add_val hace que el compilador no desee incluir dos veces).
#include <iostream>
namespace {
double a;
void b(double x)
{
a -= x;
}
void add_val(double x)
{
a += x;
if(x==0.01) b(0);
if(x==0.02) b(0.6);
if(x==0.03) b(-0.1);
if(x==0.04) b(0.4);
}
}
int main()
{
a = 0;
for(int i=0; i<1000000000; ++i)
{
add_val(i*1e-10);
}
std::cout << a << ''/n'';
return 0;
}
El ejemplo muestra que las personas del proyecto al que se unió no entienden los espacios de nombres anónimos :)
namespace {
const int SIZE_OF_ARRAY_X;
const int SIZE_OF_ARRAY_Y;
No es necesario que estén en un espacio de nombre anónimo, ya que el objeto const
ya tiene un enlace estático y, por lo tanto, no puede entrar en conflicto con los identificadores del mismo nombre en otra unidad de traducción.
bool getState(userType*,otherUserType*);
}
Y esto es en realidad una pesimista: getState()
tiene un enlace externo. Por lo general, es mejor preferir el enlace estático, ya que eso no contamina la tabla de símbolos. Es mejor escribir
static bool getState(/*...*/);
aquí. Caí en la misma trampa (hay texto en el estándar que sugiere que la estática de archivos está obsoleta en favor de espacios de nombres anónimos), pero trabajando en un gran proyecto de C ++ como KDE, obtienes mucha gente que te gira la cabeza de la manera correcta alrededor de nuevo :)
El espacio de nombre sin nombre limita el acceso de clase, variable, función y objetos al archivo en el que está definido. La funcionalidad del espacio de nombres sin nombre es similar a static
palabra clave static
en C / C ++.
static
palabra clave static
limita el acceso de la variable global y la función al archivo en el que están definidos.
Existe una diferencia entre el espacio de nombre sin nombre y static
palabra clave static
debido a que el espacio de nombre sin nombre tiene una ventaja sobre la estática. static
palabra clave static
se puede usar con variable, función y objetos pero no con clase definida por el usuario.
Por ejemplo:
static int x; // Correct
Pero,
static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong
Pero lo mismo puede ser posible con el espacio de nombre sin nombre. Por ejemplo,
namespace {
class xyz {/*Body of class*/}
static structure {/*Body of structure*/}
} //Correct
Tener algo en un espacio de nombre anónimo significa que es local para esta unidad de traducción (archivo .cpp y todo lo que incluye), esto significa que si otro símbolo con el mismo nombre está definido en otra parte, no habrá una violación de la Regla de Una Definición (ODR).
Esto es lo mismo que la forma C de tener una variable estática global o función estática, pero también se puede usar para definiciones de clase (y se debe usar en lugar de static
en C ++).
Todos los espacios de nombres anónimos en el mismo archivo se tratan como el mismo espacio de nombres y todos los espacios de nombres anónimos en archivos diferentes son distintos. Un espacio de nombre anónimo es el equivalente de:
namespace __unique_compiler_generated_identifer0x42 {
...
}
using namespace __unique_compiler_generated_identifer0x42;
Un espacio de nombre anónimo hace que las variables, funciones, clases, etc. incluidas solo estén disponibles dentro de ese archivo. En su ejemplo, es una forma de evitar las variables globales. No hay diferencia de tiempo de ejecución o tiempo de compilación.
No hay tanta ventaja o desventaja aparte de "¿quiero que esta variable, función, clase, etc. sea pública o privada?"