2011-02-02 18 views
24

Durante la lectura de Bruce Eckel de "Pensando en C++" sobre espacios de nombres, me encontré con la siguiente declaración:¿Por qué incluir "usar el espacio de nombres" en un archivo de encabezado es una mala idea en C++?

Sin embargo, usted casi nunca se ve un directiva using en un fichero de cabecera (al menos no fuera de alcance) El motivo es que el uso de la directiva elimina la protección de ese espacio de nombres particular , y el efecto dura hasta el final de la unidad de compilación actual . Si se pone un usando Directiva (fuera de alcance) en un archivo cabecera, significa que esta pérdida de "protección del espacio de nombres" ocurrirá dentro cualquier archivo que incluye esta cabecera , que a menudo significa que otros archivos de cabecera.

¿Podría ayudarme a comprender la afirmación anterior con un ejemplo fácil?

+3

Yeap, aquí tienes: http://stackoverflow.com/questions/2152925/can-i-undo-the-effect-of-using-namespace-in-c – sharptooth

+4

@sharptooth: "Let me Stackoverflow eso para ti "apareció en mi cabeza :) – Mehrdad

+0

@Mehrdad: LOL, espero que nunca lleguemos a esa etapa. – sharptooth

Respuesta

25

consideran 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 intenta compilar, verá 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 se requiere el ::string definido por el usuario o std::string incluido.

Ahora imagina que toma la parte superior del programa ... las líneas 1 a 5 - hasta e incluyendo el struct string ... y ponerlo en un archivo de cabecera que luego #include antes main(). Nada cambia: todavía tienes un error. Por lo tanto, al igual que para los programas independientes, los archivos de encabezado con declaraciones using en ellos pueden causar problemas para otros códigos que los incluyen, lo que hace que algunas de sus declaraciones sean ambiguas.

Puede ser un dolor más grande, ya que los encabezados se pueden incluir, directa o indirectamente, arbitrariamente grandes cantidades de código dependiente, y ...

  • retirar la declaración using de la cabecera, o
  • un cambio en el contenido de <string>, o cualquier otro encabezado que afecta std::

... podría romper el código incluyendo la cabecera problemática. Cualquiera de los dos problemas puede hacer que el código dependiente no se pueda compilar, y es posible que los problemas no se noten hasta que se intente otra compilación. Además, la persona que sufre debido a la declaración using puede no tener permisos de sistema de archivos/repositorio de código, autoridad corporativa, etc. para eliminar la declaración using del encabezado, ni corregir 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.

+0

buena explicación ... muchas gracias – user388338

+0

@ user388338: de nada ... aplausos. –

15

Si un encabezado contiene using namespace std, todo, desde ese espacio de nombre, se agrega el espacio de nombre global en cada módulo que incluye el encabezado.

Esto significa que nunca puede declarar una función o definir una clase con el mismo nombre (y parámetros compatibles para una función) como una función/clase std en el espacio de nombres global en cualquiera de esos módulos.

+0

muchas gracias .. – user388338

+1

"nunca se puede declarar una función o definir una clase con el mismo nombre" - en realidad, es solo que la persona que llama tiene que desambiguar el uso, y al hacerlo la versión global se corresponde preferentemente con ':: identifier', mientras que la versión" utilizada "debe ser accedida como' :: std :: identifier'. Curiosamente, si no hay ambigüedad, el ':: identificador' explícito encuentra la versión "usada", por lo que su "todo de ese espacio de nombres se agrega [al] global" es la perspectiva correcta ... es más que solo una ubicación de búsqueda implícita secundaria para identificadores sin un prefijo '::' .... –

4

Bueno, de qué sirve 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 utiliza 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 (por lo que se mantienen separados el uno del otro).

Si luego poner using A; y using B; en las cabeceras, este se moverá A :: FooBar y B :: FooBar sólo FooBar, traer de vuelta a la colisión, la eliminación de la ganancia del uso de espacios de nombres en el primer lugar.

4

Copia el siguiente párrafo de "C++ Primer, quinta edición":

código dentro de las cabeceras de ordinario no debe utilizar using declaraciones. El motivo es que los contenidos de un encabezado se copian en el texto del programa incluido . Si un encabezado tiene una declaración using, entonces cada programa que incluye ese encabezado obtiene esa misma declaración de uso. Como resultado de , un programa que no intenta utilizar el nombre de biblioteca especificado puede encontrar conflictos de nombres inesperados.

Cuestiones relacionadas