¿Por qué el "uso de espacio de nombres estándar" se considera una mala práctica?

Me dijeron que escribir código using namespace std en el código es incorrecto, y que debería usar std::cout y std::cin lugar.

¿Por qué el using namespace std considera una mala práctica? ¿Es ineficaz o puede declarar variables ambiguas (variables que tienen el mismo nombre que una función en el std )? ¿Afecta el rendimiento?

2212
21 сент. establecido por akbiggs el 21 de septiembre 2009-09-21 06:08 '09 a las 6:08 am 2009-09-21 06:08
@ 36 respuestas
  • 1
  • 2

Esto no está relacionado con el rendimiento en absoluto. Pero considera esto: usas dos bibliotecas llamadas Foo y Bar:

 using namespace foo; using namespace bar; 

Todo funciona bien, puedes llamar a Blah() desde Foo y Quux() desde Bar sin ningún problema. Pero un día te estás mudando a una nueva versión de Foo 2.0, que ahora ofrece una característica llamada Quux() . Ahora tiene un conflicto: tanto Foo 2.0 como Bar importan Quux() en su espacio de nombres global. Esto requerirá un poco de esfuerzo para solucionarlo, especialmente si los parámetros de la función son los mismos.

Si usó foo::Blah() y bar::Quux() , entonces la introducción de foo::Quux() no sería un evento.

1863
21 сент. respuesta dada por Greg Hewgill 21 de septiembre 2009-09-21 06:13 '09 a las 6:13 2009-09-21 06:13

Estoy de acuerdo con todo lo que Greg escribió , pero me gustaría agregar: ¡Incluso puede ser peor de lo que Greg dijo!

La biblioteca Foo 2.0 puede introducir la función Quux() , que es definitivamente una mejor combinación para algunas de sus llamadas de Quux() que bar::Quux() , cuyo código ha sido llamado durante muchos años. Entonces su código aún se compila , pero calla silenciosamente la función y Dios sabe qué. Esto es tan malo como todo puede ser.

Tenga en cuenta que el std contiene muchos identificadores, muchos de los cuales son muy comunes ( list reflexión, sort , string , iterator , etc.), que probablemente también aparezcan en otro código.

Si crees que esto es poco probable: hubo una pregunta que describe cómo sucedió (función incorrecta causada por la falta del prefijo std:: :). alrededor de medio año después de dar esta respuesta. Aquí hay otro ejemplo más reciente de tal pregunta. Este es el verdadero problema.


Aquí hay otro punto de datos: hace muchos años, también me acostumbré a suponer que esto molesta la necesidad de un prefijo para todos los de la biblioteca estándar std:: . Luego trabajé en un proyecto donde al principio se decidió que las directivas y las declaraciones de using están prohibidas, con la excepción de las áreas de función. Adivina qué? La mayoría de nosotros hemos tenido muy pocas semanas para acostumbrarnos a escribir el prefijo, y después de algunas semanas, la mayoría de nosotros incluso estuvimos de acuerdo en que realmente hizo que el código fuera más legible. Hay una razón para esto: si te gusta la prosa más corta o más larga, es subjetiva, pero los prefijos agregan objetivamente claridad al código. No solo el compilador, sino que también es más fácil para usted ver qué identificador se menciona.

En diez años, este proyecto ha crecido a varios millones de líneas de código. Dado que estas discusiones surgen una y otra vez, una vez tuve curiosidad por la frecuencia using usó el using área de función (permitida) en el proyecto. Encontré fuentes para esto y solo encontré una o dos docenas de lugares donde se usó. Para mí, esto indica que, una vez probado, los desarrolladores no encuentran std:: suficientemente doloroso como para usar directivas, incluso una vez cada 100 kLoC, incluso cuando se permite su uso.


En pocas palabras: prefijar explícitamente todo no daña, se usa muy poco y tiene ventajas objetivas. En particular, simplifica la interpretación del código por el compilador y los lectores humanos, y este probablemente debería ser el objetivo principal al escribir el código.

1214
21 сент. la respuesta es dada sbi 21 sep 2009-09-21 12:26 '09 a las 12:26 2009-09-21 12:26

El problema con el using namespace de using namespace en los archivos de encabezado de sus clases es que obliga a cualquier persona que quiera usar sus clases (incluidos los archivos de encabezado) a que también "use" (es decir, vea todo) estos otros espacios de nombres.

Sin embargo, puede usar libremente la declaración de uso en sus archivos (privados) * .cpp.


Recuerde que algunas personas no están de acuerdo con mi declaración de "sentirse libre" como esta, porque aunque el uso de la declaración cpp es mejor que el encabezado (porque no afecta a las personas que incluyen su archivo de encabezado), piensan que esto todavía no es bueno (porque, dependiendo del código, esto puede complicar la implementación de la clase). Este tema de preguntas frecuentes dice

La directiva de uso existe para el código C ++ obsoleto y para facilitar la transición a los espacios de nombres, pero probablemente no debería usarlo regularmente, al menos en el nuevo código C ++.

El FAQ ofrece dos alternativas:

  • Declaración de uso:

     using std::cout; // a using-declaration lets you use cout without qualification cout << "Values:"; 
  • Sólo escribe std ::

     std::cout << "Values:"; 
337
21 сент. respuesta dada por ChrisW 21 de septiembre 2009-09-21 06:22 '09 a las 6:22 am 2009-09-21 06:22

Recientemente me enfrenté a una queja sobre Visual Studio 2010 . Resultó que casi todos los archivos fuente tienen dos líneas:

 using namespace std; using namespace boost; 

Muchas funciones de Boost están incluidas en el estándar C ++ 0x, y Visual Studio 2010 tiene una gran cantidad de C ++ 0x, por lo que estos programas no se compilaron.

Por lo tanto, evitando using namespace X; Esta es una forma de verificación futura, una forma de asegurar que los cambios en las bibliotecas utilizadas y / o los archivos de encabezado no interrumpan el programa.

213
28 окт. Responder David Thornley 28 de octubre 2010-10-28 20:37 '10 a las 20:37 2010-10-28 20:37

Versión corta: no utilice el uso global de declaraciones o directivas en los archivos de encabezado. Siéntase libre de usarlos en sus archivos de implementación. Aquí, lo que Herb Sutter y Andrei Aleksandrescu tienen que decir sobre este tema en los Estándares de codificación de C ++ (negrita para mi atención):

Resumen

Los nombres de los espacios de nombres son para su conveniencia, no para otros: nunca escriba una declaración de uso o una directiva de uso antes de una directiva #include.

Consecuencia: no registre el nivel de espacio de nombres en los archivos de encabezado usando directivas o usando declaraciones; en cambio, el espacio de nombres claramente califica todos los nombres. (La segunda regla se sigue de la primera, porque los encabezados nunca pueden saber que un encabezado #includes diferente puede aparecer después de ellos).

Hablar

En resumen: puede y debe usar el espacio de nombres con declaraciones y directivas en sus archivos de implementación después de #incluir y sentirse bien. A pesar de las repetidas afirmaciones en contrario, el espacio de nombres que usa declaraciones y directivas no es malo, y no persiguen el objetivo de los espacios de nombres. Más bien, es lo que le permite usar espacios de nombres .

178
03 нояб. respuesta dada por mattnewport 03 nov. 2014-11-03 23:00 '14 a las 23:00 2014-11-03 23:00

No puede utilizar una directiva a escala global, especialmente en los encabezados. Sin embargo, hay situaciones en las que esto se aplica incluso en el archivo de encabezado:

 template <typename FloatType> inline FloatType compute_something(FloatType x) { using namespace std; //no problem since scope is limited return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4)); } 

Esto es mejor que la calificación explícita ( std::sin , std::cos ...) porque es más corto y tiene la capacidad de trabajar con tipos de punto flotante definidos por el usuario (a través de la búsqueda dependiente del argumento).

110
21 сент. la respuesta se da robson3.14 21 sep . 2009-09-21 18:47 '09 a las 18:47 2009-09-21 18:47

No lo uses globalmente.

Se considera "malo" solo cuando se usa globalmente . Porque:

  • Usted desordena el espacio de nombres en el que está programando.
  • Los lectores tendrán dificultades para ver de dónde proviene un identificador en particular cuando utiliza mucho el using namespace xyz .
  • Lo que sea cierto para otros lectores de su código fuente, esto es aún más cierto para el lector más frecuente: usted mismo. Vuelve en uno o dos años y verás ...
  • Si solo habla sobre el using namespace std , es posible que no sepa sobre todos los materiales que capture, y cuando agregue otro #include o #include a una nueva versión de C ++, puede que tenga conflictos de nombres que no conocía.

Puedes usarlo localmente.

Adelante y utilízalo localmente (casi) libremente. Esto, por supuesto, evita la repetición de std:: - y la repetición también es mala.

Idioma para uso local.

En C ++ 03, había un modismo - código de plantilla - para implementar la función de swap para sus clases. Se ha sugerido que realmente uses local using namespace std , o al menos using std::swap :

 class Thing { int value_; Child child_; public: // ... friend void swap(Thing  Thing  }; void swap(Thing  Thing  { using namespace std; // make `std::swap` available // swap all members swap(a.value_, b.value_); // `std::stwap(int, int)` swap(a.child_, b.child_); // `swap(Child or `std::swap(...)` } 

Hace la siguiente magia:

  • El compilador seleccionará std::swap for value_ , es decir, void std::swap(int, int) .
  • Si tiene implementada una sobrecarga de void swap(Child Child> , el compilador la seleccionará.
  • Si no tiene esta sobrecarga, el compilador utilizará void std::swap(Child> e intentará reemplazarlos mejor.

C ++ 11 ya no es motivo para usar esta plantilla. La implementación de std::swap se ha modificado para encontrar una posible sobrecarga y seleccionarla.

86
18 янв. La respuesta la da el 18 de enero. 2013-01-18 12:34 '13 a las 12:34 2013-01-18 12:34

Si importa los archivos de encabezado correctos, de repente tendrá nombres como hex , left , plus o count en su escala global. Esto puede ser sorprendente si no sabe que std:: contiene estos nombres. Si también intenta usar estos nombres localmente, esto puede llevar a cierta confusión.

Si todos los elementos estándar están en su propio espacio de nombres, no debe preocuparse por los conflictos de nombres con su código u otras bibliotecas.

73
21 сент. La respuesta se da sth 21 sep. 2009-09-21 06:23 '09 a las 6:23 am 2009-09-21 06:23

Los programadores experimentados utilizan todo lo que resuelve sus problemas y evitan cualquier problema nuevo que surja, y evitan el uso de directivas de puntero en el nivel de encabezado por esta razón exacta.

Los programadores experimentados también intentan evitar calificar completamente los nombres dentro de sus archivos fuente. Una razón menor para esto es que no es elegante escribir más código si no hay suficiente código, si no hay razones convincentes. La razón principal de esto es que el argumento dependiente de la búsqueda (ADL) está deshabilitado.

¿Cuáles son estas buenas razones? A veces, los programadores obviamente desean deshabilitar ADL, en otros casos quieren eliminar la ambigüedad.

Entonces, todo está en orden:

  • Uso de directivas a nivel de funciones y uso de declaraciones dentro de la implementación de funciones
  • Declaraciones de nivel de fuente de uso en archivos de origen
  • (A veces) usando-en el nivel del archivo fuente
39
29 марта '11 в 11:10 2011-03-29 11:10 Alexander Poluektov da la respuesta el 29 de marzo de 2011 a las 11:10 2011-03-29 11:10

Otra razón es una sorpresa.

Si veo cout << blah lugar de std::cout << blah

Creo que ¿qué es esto cout ? ¿Es eso un cout normal? ¿Es esto algo especial?

37
21 сент. Respuesta dada por Martin Beckett el 21 de septiembre. 2009-09-21 06:13 '09 a las 6:13 2009-09-21 06:13

Estoy de acuerdo en que no se puede usar globalmente, pero no es tan malo usarlo localmente, como en el namespace . Aquí hay un ejemplo del "lenguaje de programación C ++":

 namespace My_lib { using namespace His_lib; // everything from His_lib using namespace Her_lib; // everything from Her_lib using His_lib::String; // resolve potential clash in favor of His_lib using Her_lib::Vector; // resolve potential clash in favor of Her_lib } 

En este ejemplo, resolvimos las posibles colisiones de nombres y las ambigüedades asociadas con su composición.

Los nombres declarados explícitamente allí (incluidos los nombres declarados usando declaraciones como His_lib::String ) tienen prioridad sobre los nombres que están disponibles en otra área usando la directiva using namespace Her_lib ( using namespace Her_lib ).

36
29 авг. La respuesta se da Oleksiy 29 de agosto. 2013-08-29 12:44 '13 a las 12:44 2013-08-29 12:44

También considero que esto es una mala práctica. Por que Solo una vez pensé que la función del espacio de nombres es dividir el material para que no lo estropee arrojando todo en una bolsa global. Sin embargo, si uso a menudo "cout" y "cin", escribo: using std::cout; using std::cin; using std::cout; using std::cin; en el archivo cpp (nunca en el archivo de encabezado, ya que se distribuye utilizando #include ). Creo que nadie cuerdo nunca llamará a un stream cout o cin .

26
21 сент. La respuesta se da Yelonek 21 sep . 2009-09-21 12:34 '09 a las 12:34 2009-09-21 12:34

Es bueno ver el código y saber lo que hace. Si veo std::cout , sé que el flujo de cout de la biblioteca std . Si veo un cout , entonces no lo sé. Este puede ser el flujo de cout de la biblioteca std . O tal vez int cout = 0; Diez líneas más altas en la misma función. O una variable static llamada cout en este archivo. Podría ser cualquier cosa.

Ahora tome un código de línea de un millón que no es particularmente grande, y está buscando un error, lo que significa que sabe que hay una línea en este millón de líneas que no hace lo que se supone que debe hacerse. cout << 1; puede leer un cout static int denominado cout , desplazarlo un bit a la izquierda y descartar el resultado. Buscando un error, tengo que comprobarlo. ¿Ves cómo realmente prefiero ver std::cout ?

Esta es una de estas cosas que parece una muy buena idea si usted es un maestro y nunca ha tenido que escribir y mantener ningún código para vivir. Me gusta ver el código donde (1) sé lo que hace; y, (2) estoy seguro de que la persona que escribe esto sabía lo que estaba haciendo.

21
13 марта '14 в 20:22 2014-03-13 20:22 la respuesta se da gnasher729 13 de marzo de 2014 a las 20:22 2014-03-13 20:22

Todo sobre la gestión de la complejidad. El uso de un espacio de nombres conducirá a algo que no desea, y por lo tanto puede ser más difícil de depurar (tal vez lo digo). Usar std :: everywhere es más difícil de leer (más texto y todo eso).

Caballos para cursos: gestione su complejidad de la manera que pueda y pueda sentir.

20
21 сент. La respuesta se da Preet Sangha 21 sep . 2009-09-21 06:14 '09 a las 6:14 am 2009-09-21 06:14

Usar muchos espacios de nombres al mismo tiempo parece ser una receta para el desastre, pero usar JUST espacio de nombres std y solo std nombres std no es un gran problema, en mi opinión, porque la redefinición solo puede ocurrir por su propio código ... .

Entonces, considérelos como nombres reservados, como "int" o "clase", y eso es todo.

La gente debería dejar de ser tan anal. Tu profesor tenía razón todo el tiempo. Solo usa UN espacio de nombres; ese es el punto central del uso de espacios de nombres en primer lugar. No debe usar más de uno a la vez. Si esto no es tuyo. Así que la redefinición no va a suceder.

17
09 нояб. respuesta dada por el usuario2645752 09 nov. 2013-11-09 18:09 '13 a las 18:09 2013-11-09 18:09
  • Debe poder leer el código escrito por personas que tienen diferentes opiniones sobre el estilo y las mejores prácticas que usted.

  • Si usas cout, nadie se avergüenza. Pero cuando tienes muchos espacios de nombres que vuelan, y ves esta clase, y no estás muy seguro de lo que hace, porque el espacio de nombres explícito actúa como una especie de comentario. Puede ver de un vistazo: "Oh, esto es una operación del sistema de archivos" o "Lo que hace que la red funcione".

17
21 сент. la respuesta es dada por Dustin Getz 21 sep. 2009-09-21 07:04 '09 a las 7:04 2009-09-21 07:04

Consideraré

 // myHeader.h #include <sstream> using namespace std; // someoneElses.cpp/h #include "myHeader.h" class stringstream { // uh oh }; 

Tenga en cuenta que este es un ejemplo simple, si tiene archivos con 20 incluidos y otras importaciones, tendrá muchas dependencias para solucionar el problema. Lo peor de todo es que puede obtener errores no relacionados en otros módulos, dependiendo de las definiciones que entren en conflicto.

No es terrible, pero se librará de los dolores de cabeza al no usarlos en los archivos de cabecera o en el espacio de nombres global. Lo más probable es que esto se pueda hacer en áreas muy limitadas, pero nunca he tenido problemas para ingresar 5 caracteres adicionales para averiguar de dónde provienen mis funciones.

16
21 сент. la respuesta la da Ron Warholic el 21 sep . 2009-09-21 06:19 '09 a las 6:19 AM 2009-09-21 06:19

Un ejemplo específico para aclarar el problema. Imagina que tienes una situación en la que tienes 2 bibliotecas, foo y bar, cada una con su propio espacio de nombres:

 namespace foo { void a(float) {  } } namespace bar { ... } 

Ahora digamos que usa foo y barra juntos en su propio programa de la siguiente manera:

 using namespace foo; using namespace bar; void main() { a(42); } 

En este punto, todo está en orden. Cuando ejecutas tu programa, "hace algo". Pero luego actualizas el panel y dices que ha cambiado así:

 namespace bar { void a(float) {  } } 

En este punto, obtendrá un error de compilación:

 using namespace foo; using namespace bar; void main() { a(42); // error: call to 'a' is ambiguous, should be foo::a(42) } 

Por lo tanto, deberá realizar algunas tareas de mantenimiento para aclarar qué significa "a" (es decir, foo::a ). Probablemente esto sea indeseable, pero, afortunadamente, es bastante simple (solo agregue foo:: antes de todas las llamadas que el compilador marca como ambiguas).

Pero imagine un escenario alternativo en el que la barra, en cambio, haya cambiado para verse así:

 namespace bar { void a(int) {  } } 

En este punto, su llamada a a(42) se une repentinamente a bar::a lugar de foo::a y en lugar de hacer algo, hace algo completamente diferente. No hay advertencia de compilador o cualquier otra cosa. Tu programa comienza a hacer algo completamente diferente que antes.

Cuando utiliza un espacio de nombres, corre el riesgo de un escenario similar, por lo que las personas se sienten incómodas al usar espacios de nombres. Cuantas más cosas haya en el espacio de nombres, mayor será el riesgo de conflicto, por lo que las personas pueden ser aún más incómodas para usar el espacio de nombres estándar (debido a la cantidad de cosas en este espacio de nombres) que otros espacios de nombres.

En última instancia, este es un compromiso entre la capacidad de grabación y la confiabilidad / mantenimiento. La legibilidad también puede importar, pero puedo ver los argumentos para esto de todos modos. Normalmente, diría que la confiabilidad y la capacidad de mantenimiento son más importantes, pero en este caso usted pagará constantemente los costos de registro para una confiabilidad / mantenibilidad bastante rara. La "mejor" compensación determinará su proyecto y sus prioridades.

11
02 сент. La respuesta la da Kevin 02 sep. 2016-09-02 23:06 '16 a las 11:06 pm 2016-09-02 23:06

El espacio de nombres es un ámbito con nombre. Los espacios de nombres se utilizan para agrupar declaraciones relacionadas y mantener elementos separados por separado. Например, две отдельно разработанные библиотеки могут использовать одно и то же имя для обозначения разных но пользователь может использовать оба:

 namespace Mylib{ template<class T> class Stack{  }; / / ... } namespace Yourlib{ class Stack{  }; / / ... } void f(int max) { Mylib: :Stack<int> s1(max) ; / / use my stack Yourlib: :Stack s2(max) ; / / use your stack / / ... } 

Повторение имени пространства имен может быть отвлечением как для читателей, так и для писателей. Следовательно, возможно чтобы указать, что имена из определенного пространства имен доступны без явной квалификации. Por ejemplo:

 void f(int max) { using namespace Mylib; / / make names from Mylib accessible Stack<int> s1(max) ; / / use my stack Yourlib: :Stack s2(max) ; / / use your stack / / ... }