Mientras leía “Thinking in C++” de Bruce Eckel sobre espacios de nombres, encontré la siguiente declaración:
Sin embargo, prácticamente nunca verá una directiva de uso en un archivo de encabezado (al menos no fuera del alcance). La razón es que la directiva using elimina la protección de ese espacio de nombres en particular, y el efecto dura hasta el final de la unidad de compilación actual. Si coloca una directiva de uso (fuera de un alcance) en un archivo de encabezado, significa que esta pérdida de “protección de espacio de nombres” ocurrirá dentro de cualquier archivo que incluya este encabezado, lo que a menudo significa otros archivos de encabezado.
¿Le gustaría ayudarme a comprender la declaración anterior con algún ejemplo fácil?
Considere este programa:
line#
1 #include <string>
2
3 using namespace std;
4
5 struct string { const char* p; }; // Beware: another string!
6
7 int main()
8 {
9 string x; // Error: ambiguous - which string is wanted?
10 }
Si intentas compilarlo, verás errores:
g++ using.cc -o using
using.cc: In function `int main()':
using.cc:9: error: use of `string' is ambiguous
using.cc:5: error: first declared as `struct string' here
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stringfwd.h:60: error:
also declared as `typedef struct std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::string' here
using.cc:9: error: `string' was not declared in this scope
using.cc:9: error: expected `;' before "x"
El problema aquí es que cuando main()
especifica string x;
el compilador no está seguro de si el definido por el usuario ::string
o incluido std::string
se busca
Ahora imagina que tomas la parte superior del programa… líneas 1 a 5 – hasta e incluyendo el struct string
… y colóquelo en un archivo de encabezado que luego #include
antes de main()
. Nada cambia: todavía tienes un error. Entonces, al igual que con los programas independientes, los archivos de encabezado con using
las declaraciones en ellos pueden causar problemas para otro código que los incluye, haciendo que algunas de sus declaraciones sean ambiguas.
Sin embargo, puede ser un dolor mayor, ya que los encabezados pueden incluirse, directa o indirectamente, por cantidades arbitrariamente grandes de código dependiente, y…
- la eliminación de la
using
declaración del encabezado, o
- un cambio en el contenido de
<string>
o cualquier otro encabezado que afecte std::
… podría romper el código, incluido el encabezado problemático. Cualquiera de los problemas puede hacer que el código dependiente no se pueda compilar, y es posible que ni siquiera se noten los problemas hasta que se intente otra compilación. Además, la persona que sufre debido a la using
la declaración puede no tener permisos de sistema de archivos/repositorio de código, autoridad corporativa, etc. para eliminar el using
declaración del encabezado, ni arreglar otro código de cliente afectado.
Dicho esto, si un encabezado solo tiene “uso” dentro de una clase o función, entonces no hay efecto en el código más allá de ese alcance, por lo que el impacto potencial de los cambios en std:: se reduce drásticamente.
Bueno, ¿cuál es el punto de usar espacios de nombres? Es para evitar el riesgo de colisiones de nombres.
Digamos que tiene un nombre de clase bastante común, por ejemplo, FooBar. Si usa varias bibliotecas, existe el riesgo de que FooBar en la biblioteca A colisione con FooBar en la biblioteca B. Para eso usamos dos espacios de nombres diferentes A y B, para mover los FooBars del espacio de nombres global a A::FooBar y B::FooBar (para que se mantengan separados unos de otros).
Si luego pones using A;
y using B;
en los encabezados, esto moverá A::FooBar y B::FooBar solo a FooBar, trayendo de vuelta la colisión, eliminando la ganancia del uso de espacios de nombres en primer lugar.
Sí, aquí tienes: stackoverflow.com/questions/2152925/…
– diente filoso
2 de febrero de 2011 a las 8:53